Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Объектно-ориентированный подход в С


Автор: anthony 25.9.2007, 15:08
Задача состоит в анализе возможностей использования объектно-ориентированной методологии в С.
Remark. Проект Laurent Deniau во многом ориентирован на другой подход к решению этой проблемы, однако проведение аналогий с ним или точное указание на использованные там механизмы приветствуется.
Рассмотрим код С, который демонстрирует динамическое связывание функций.
Данный код иллюстрирует использование возможности корректной реализации полиморфизма в С без использования каких либо расширений. Полная реализация находится в прилагаемом архиве.
Извиняюсь за небрежности в написании тестовой части, однако, она создана как временный пример. В то время как описание ядра является полным и корректным.

Код

#include <stdio.h>
#include <stdlib.h>
#include "objects_targeting.h"
#include "objects_object.h"
#include "shape.h"
#include "shape_circle.h"
#include "shape_square.h"

#define OBJECTS_COUNT 2

int main ( void ) {
    Object_Ref *objects = malloc ( sizeof ( *objects ) * OBJECTS_COUNT );

    objects [ 0 ] = ( Object_Ref ) shape_circle_create ( 1 );
    objects [ 1 ] = ( Object_Ref ) shape_square_create ( 2 );

    for ( int object_index = 0; object_index < OBJECTS_COUNT; ++object_index ) {
        char *object_string = OBJECT ( objects [ object_index ] )->to_string ( );
        ( void ) printf ( "%s\n", object_string );

        objects_free ( object_string );
    }

    for ( int object_index = 0; object_index < OBJECTS_COUNT; ++object_index ) {
        OBJECT ( objects [ object_index ] )->destroy ( );
    }

    free ( objects );
    return 0;
}


Вопросы
  • Насколько обусловлено использование макросов для определения цели вызова, а не фактическая передача указателей на объекты-являющиеся целями вызова (как в gtk+).
  • Ваше общее мнение о дизайне, стиле программирования и так далее.
  • Замеченные ошибки, неточности (особенно семантические или стилистические).
  • Есть ли у кого-нибудь идеи по реализации интерфейсов. Целостность при динамическом приведении типов обеспечивается построением структуры на основе указателей, имеющих фиксированный размер и порядка их следования. Такой подход применим для одиночного наследования, однако не применим для множественного или для интерфейсов.
  • Можно ли написать макрос для быстрой реализации прокси-функции.

PS. Анализ данного кода требует некоторого знания С и объектно-ориентированной методологии (в частности, определение цели вызова и полиморфизм).

Автор: Lazin 25.9.2007, 16:42
Прикольно конечно, но мне кажется не очень эффективно по причине того, что для доступа на уровень иерархии N, нужно использовать N косвенных обращений. 
То есть если у нас есть класс Shape_Circle производный от Shape, который в свою очередь является производным от Object, то для доступа к методам или свойствам Object получится цепочка shape_circle->super->super_->call(). 
Мне кажется можно попытаться сделать это по другому:

Код


typedef char * ( *object_to_string ) ( void );

typedef void ( *object_destroy ) ( void* );

//интерфейс "базового" класса
#define DECLARE_BASE_INTERFACE \ //vtable
      object_to_string to_str;\
      object_destroy free;\
      //data
      int type_info;\

typedef struct Base
{
 DECLARE_BASE_INTERFACE
};

#define FOO 1
typedef struct Foo
{
 DECLARE_BASE_INTERFACE
 //foo members
 int foo;
};

//виртуальный деструктор Foo
void foo_destroy ( void* this)
{
  free((Foo*)this);
}

//конструктор Foo
Base* new_foo(int data)
{
  Foo* f = malloc( sizeof(Foo) );
  f->foo = data;
  f->type_info = FOO;
  f->free = &foo_destroy();
  ****
  return f;
}

//использование
//создаём
Base* b = new_foo(9);
//вызов метода (1й параметр - this)
b->to_str(b);
//деструктор
b->free(b);

Это может работать потому что структура Foo состоит из тех - же элементов что и Base, плюс свои данные. Поэтому можно обращаться к Foo через указатель на Base. Каждому методу нужно передавать указатель на объект для которого происходит вызов.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)