Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11634
Последний выпуск: 19.06.2015

ООП и язык C

Эта статья продолжает тему имитации C++ на чистом C. В данной статье я расскажу как в стиле чистого C организовать обработку данных различного типа, которые могут находится "под одной крышей", например в односвязных или двусвязных списках.

Итак предположим, что у нас есть структура данных описывающая точку в двух координатах, и есть структура данных описывающая точку в трёх координатах. Стандартное C++ решение выглядит так:

class Point2D {
  public:
    float x,y;
    Point2D() {
       x = y = 0;
       }
    virtual void Draw(){ coutDraw();
  }

Итак класс Point3D наследует класс Point2D.

Есть виртуальный метод Draw. Предположим, что у нас есть список, элементами которого являются указатели на обьекты как типа Point2D, так и типа Point3D. И есть функция "обёртка" DrawXObject вызывающая метод Draw для любого из обьектов. Мы вызываем Draw через указатель на базовый класс, и так как метод виртуальный, то для каждого обьекта вызовится своя реализация метода. Что нам и нужно. Всё красиво и просто.

Но это в C++. Попробуем повторить это по сишному.

Кому код приведённый ниже покажется не понятным, то читайте предыдущую статью, а эту отложите до лучших времён. Дальше код, а потом обьяснения. Как и в прошлый раз BorlandC++Builder4.0 -> Console Application

#pragma hdrstop
#include 
#include 
#include 

#pragma argsused

enum TAGS {
t_Point2D,
t_Point3D
};

extern "C" void Point2D_method_Draw(void* _this);
extern "C" void Point2D_method_Init(void* _this);

typedef void (*Point2D_fn_Init)(void*);
typedef void (*Point2D_fn_Draw)(void*);

typedef struct {

int tag;
float x,
y;

static Point2D_fn_Init Init;
static Point2D_fn_Draw Draw;

}Point2D;

Point2D_fn_Init Point2D :: Init = Point2D_method_Init;
Point2D_fn_Draw Point2D :: Draw = Point2D_method_Draw;

extern "C" void Point3D_method_Draw(void* _this);
extern "C" void Point3D_method_Init(void* _this);

typedef void (*Point3D_fn_Init)(void*);
typedef void (*Point3D_fn_Draw)(void*);

typedef struct {

int tag;
float x,
y,
z;

static Point3D_fn_Init Init;
static Point3D_fn_Draw Draw;

}Point3D;

Point3D_fn_Init Point3D :: Init = Point3D_method_Init;
Point3D_fn_Draw Point3D :: Draw = Point3D_method_Draw;

void Point2D_method_Init(void* _this)
{
Point2D* t = (Point2D*)_this;
t->tag = t_Point2D;
t->x = t->y = 0.0;
}

void Point2D_method_Draw(void* _this)
{
Point2D* t = (Point2D*)_this;
printf("Poin2D Draw ");
}

void Point3D_method_Init(void* _this)
{
Point3D* t = (Point3D*)_this;
t->tag = t_Point3D;
t->x = t->y = t->z = 0.0;
}

void Point3D_method_Draw(void* _this)
{
Point3D* t = (Point3D*)_this;
printf("Poin3D Draw ");
}

void DrawXObject(void* obj)
{
int tag_obj = *((int*)obj);
if(tag_obj == t_Point2D){
Point2D* p = (Point2D*)obj;
p->Draw(&p);
}
else if(tag_obj == t_Point3D){
Point3D* p = (Point3D*)obj;
p->Draw(&p);
}
}

int main(int argc, char* argv[])
{
Point2D p2d;
Point3D p3d;

p2d.Init(&p2d);
p3d.Init(&p3d);

DrawXObject(&p2d);

DrawXObject(&p3d);

getch();
return 0;
}

В структурах обьявлена переменная tag, которая инициализируется в функциях Init. Эта переменная понадобится нам в последствии, для того, чтобы определить, с каким обьектом мы имеем дело. В функции DrawXObject мы получаем значение этой переменной и принимаем решение к какому типу преобразовать полученный функцией указатель.

Помоему ничуть не хуже C++ реализации.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
465
30 января 2007 года
Jail
550 / / 30.01.2007
+0 / -1
Мне нравитсяМне не нравится
16 марта 2007, 17:49:59
А я бы сказал,что пара Java---Python выглядит намного изящнее. После этого можно навсегда забыть как о Си так и о С++. Но всё же незря до сих пор на Си ОСи пишут. Я когда начал изучать Python,то с каким же наслаждением я его учил. И припоминается мучение с которым изучался С++!!!
2.
Аноним
+1 / -1
Мне нравитсяМне не нравится
15 декабря 2005, 16:03:01
Правильно кто-то назвал С платформенно-независимым ассемблером. Его логика хорошо согласуется с логикой работы микропроцессора, но очень плохо - с внешним объектным миром. Разворот глаз С в сторону объектного мира делает программу многословной и малопонятной. Рискую навлечь на себя гнев пуристов, но ... не намного лучше дело обстоит с ясностью и трудоемкостью представления моделей объектного мира в терминах С++. Те, кто знаком с Ruby могут понять меня. Изящные и лаконичные решения Ruby для программирования объектных задач на уровне интерпретатора и не менее изящные средства пополнения арсенала объектов Ruby средствами необъектного С, если если скорость исполнения становится критичной. Так что пара чужеродных С и Ruby выглядит намного предпочтительнее пары родных С и С++.
3.
Аноним
+1 / -3
Мне нравитсяМне не нравится
28 ноября 2005, 16:37:59
хмммм. наверно, я не туда забрела...((
4.
Аноним
+1 / -0
Мне нравитсяМне не нравится
20 ноября 2005, 19:58:36
Мда, C++ для того и изобретено, чтобы избавить людей от необходимости заниматься подобными извратами.

Нет, понимаю, можно вообще все на ассемблере писать. Или уж сразу в машинных кодах, в hex-редакотре... Но зачем? Компьютеры для того и существуют, чтобы всю рутину можно было поручить им...
5.
Аноним
+2 / -2
Мне нравитсяМне не нравится
19 марта 2005, 21:48:42
Никто не мешает в чистом C сделать "ручками" vtbl.

И что это за конструкция?
[skip]
Point3D_fn_Init Point3D :: Init = Point3D_method_Init;
Point3D_fn_Draw Point3D :: Draw = Point3D_method_Draw;
[skip]
Стандарт C не описывает "::".
6.
Аноним
+2 / -0
Мне нравитсяМне не нравится
24 октября 2004, 14:41:44
функция DrawXObject должна знать все типы объектов, которые ей могут передать. При добавлении нового "подкласса" необходимо модифицировать все подобные "полиморфные" функции, тогда как в C++ этого делать не надо, в чем собственно и достоинство полиморфизма.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог