Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 12.12.2012, 18:49   #1
intmain
Играюсь с Python
Форумчанин
 
Аватар для intmain
 
Регистрация: 12.12.2012
Сообщений: 340
По умолчанию ООП на Си

ООП на обычном си без классов возможно ли (наследование, полиморфизм и другое )? И если да, то - как? Можно короткие примеры или ссылки на статьи?
Что ел то - в долг, что жил то - зря.
Для избранных. ))
Секретные разработки
intmain вне форума Ответить с цитированием
Старый 12.12.2012, 19:18   #2
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Возможно. Первые компиляторы C++ состояли из препроцессора, переводившего код в C-код и компилятора C. Полагаю, нет вопроса, возможен ли ООП на C++.
Наследование:
Код:
typedef struct {
  int value;
} Parent;

typedef struct {
  Parent p;
} Child;

//...
Child c;
c.p.value = 0;
Abstraction вне форума Ответить с цитированием
Старый 12.12.2012, 19:46   #3
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Abstraction Посмотреть сообщение
Возможно. Первые компиляторы C++ состояли из препроцессора, переводившего код в C-код и компилятора C. Полагаю, нет вопроса, возможен ли ООП на C++.
Наследование:
Код:
typedef struct {
  int value;
} Parent;

typedef struct {
  Parent p;
} Child;

//...
Child c;
c.p.value = 0;
В приведенном куске кода нет наследования. Есть агрегирование.


По сабжу: на языке си можно воссоздать все ООП механизмы. Правда делать это придется ручками, без поддержки компилятора с его технологиями.

Если я не ошибаюсь, то Кармак в своей кваке именно так и поступил: реализовал технологию полиморфизма.

Сам я правда приплюснутый, и сишечкой особо не заморачивался. Но заметил, что в различных холиварах пример с Кармаком часто используют защитники ООП, заявляя, что в крупной системе без ООП никуда. И если он там не поддерживается, значит велосипедируется в ручную.
_Bers вне форума Ответить с цитированием
Старый 12.12.2012, 20:11   #4
Perchik71
С++, Delphi
Форумчанин
 
Аватар для Perchik71
 
Регистрация: 24.11.2012
Сообщений: 495
По умолчанию

Квака 3... великолепный сорс....
но дум ещё круче.

Ваще да это не наследование....
наследование, это

Код:
class A
{
.....
}

class B: public A// разрешено идти даже в протект, но не приват
{
.....
}

class C: protected A/// запрещён протект с приватом
{
.....
}

class D: private A/// всё запрещено.
{
.....
}
Если помог, тут весы есть , Вам не сложно, а мне приятно.
Perchik71 вне форума Ответить с цитированием
Старый 12.12.2012, 20:24   #5
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

это синтаксис наследования в С++.
а не обьяснение что такое наследование.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 12.12.2012, 20:38   #6
Perchik71
С++, Delphi
Форумчанин
 
Аватар для Perchik71
 
Регистрация: 24.11.2012
Сообщений: 495
Стрелка

Наследование — один из четырёх важнейших механизмов объектно-ориентированного программирования (наряду с инкапсуляцией, полиморфизмом и абстракцией), позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом.

Другими словами, класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса
Типы наследования
Простое наследование

Класс, от которого произошло наследование, называется базовым или родительским (англ. base class). Классы, которые произошли от базового, называются потомками, наследниками или производными классами (англ. derived class).

В некоторых языках используются абстрактные классы. Абстрактный класс — это класс, содержащий хотя бы один абстрактный метод, он описан в программе, имеет поля, методы и не может использоваться для непосредственного создания объекта. То есть от абстрактного класса можно только наследовать. Объекты создаются только на основе производных классов, наследованных от абстрактного.

Например, абстрактным классом может быть базовый класс «сотрудник вуза», от которого наследуются классы «аспирант», «профессор» и т. д. Так как производные классы имеют общие поля и функции (например, поле «год рождения»), то эти члены класса могут быть описаны в базовом классе. В программе создаются объекты на основе классов «аспирант», «профессор», но нет смысла создавать объект на основе класса «сотрудник вуза».
Множественное наследование

При множественном наследовании у класса может быть более одного предка. В этом случае класс наследует методы всех предков. Достоинства такого подхода в большей гибкости. Множественное наследование реализовано в C++. Из других языков, предоставляющих эту возможность, можно отметить Python и Эйфель. Множественное наследование поддерживается в языке UML.

Множественное наследование — потенциальный источник ошибок, которые могут возникнуть из-за наличия одинаковых имен методов в предках. В языках, которые позиционируются как наследники C++ (Java, C# и др.), от множественного наследования было решено отказаться в пользу интерфейсов. Практически всегда можно обойтись без использования данного механизма. Однако, если такая необходимость все-таки возникла, то, для разрешения конфликтов использования наследованных методов с одинаковыми именами, возможно, например, применить операцию расширения видимости — «::» — для вызова конкретного метода конкретного родителя.

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

Большинство современных объектно-ориентированных языков программирования (C#, C++, Java, Delphi и др.) поддерживает возможность одновременно наследоваться от класса-предка и реализовать методы нескольких интерфейсов одним и тем же классом. Этот механизм позволяет во многом заменить множественное наследование — методы интерфейсов необходимо переопределять явно, что исключает ошибки при наследовании функциональности одинаковых методов различных классов-предков.

В C++ существует три типа наследования: public, protected, private. Спецификаторы доступа членов базового класса меняются в потомках следующим образом:

при public-наследовании все спецификаторы остаются без изменения.
при protected-наследовании все спецификаторы остаются без изменения, кроме спецификатора public, который меняется на спецификатор protected (то есть public-члены базового класса в потомках становятся protected).
при private-наследовании все спецификаторы меняются на private.

Одним из основных преимуществ public-наследования является то, что указатель на классы—наследники может быть неявно преобразован в указатель на базовый класс, то есть для примера выше можно написать:
A* a = new B;

Эта интересная особенность открывает возможность динамической идентификации типа (RTTI).

//----------

Надеюсь вопросов нет.
да и пример выше...
Если помог, тут весы есть , Вам не сложно, а мне приятно.

Последний раз редактировалось Perchik71; 12.12.2012 в 20:43.
Perchik71 вне форума Ответить с цитированием
Старый 12.12.2012, 20:46   #7
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Perchik71 Посмотреть сообщение
В C++ существует три типа наследования: public, protected, private. Спецификаторы доступа членов базового класса меняются в потомках следующим образом:
А теперь правильный ответ:

В языке с++ существует 4ре вида наследования. О трех уже было сказано выше. 4й призван решить все возможные проблемы с неоднозначностями вызовов методов. Хотя он и не является самостоятельным видом наследования, но он является одним из вариантов наследования и дополняет вышеуказанные три.

Чаще всего, его приводят в качестве примера решения проблем ромбовидных иерархий: виртуальное наследование.

http://ru.wikipedia.org/wiki/%C2%E8%...E2%E0%ED%E8%E5

Последний раз редактировалось _Bers; 12.12.2012 в 20:48.
_Bers вне форума Ответить с цитированием
Старый 12.12.2012, 20:51   #8
Perchik71
С++, Delphi
Форумчанин
 
Аватар для Perchik71
 
Регистрация: 24.11.2012
Сообщений: 495
Хорошо

Чувак, люди опухают и с этими 3...
но спасибо я запамятовал.. надо в книгу злесть...
Если помог, тут весы есть , Вам не сложно, а мне приятно.
Perchik71 вне форума Ответить с цитированием
Старый 12.12.2012, 22:05   #9
intmain
Играюсь с Python
Форумчанин
 
Аватар для intmain
 
Регистрация: 12.12.2012
Сообщений: 340
Вопрос

Я извиняюсь, но речь я вел исключительно о СИ без классов. Спасибо всем кто прокомментировал.
Я тут кое чего написал, но не пойму почему у меня нули везде когда должны быть цифры 10 20 и 30 ? И кстати вопрос, это как-то походит на наследование в пределах обычного СИ? И еще вопрос, насколько я правильно освобождаю память?

Код:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define SHAPEME(T) ((struct shape*)(T))

#define SHAPE_SHAPE   0
#define SHAPE_BOX       1
#define SHAPE_CIRCLE   2


typedef struct shape 
{
    int x;
    int y;
    int type;
   void (*shapeDraw) (struct shape* s);
} shape;


typedef struct box 
{
    struct shape baseShape;
    int someBoxProp;
} box;

typedef struct circle 
{
    struct shape baseShape;
    int someCircleProp;
} circle;

void drawShape( struct shape *s ) 
{
    printf("draw shape at position %f %f\n", s->x, s->y);
};

void drawBox( struct shape* s ) 
{
    printf("draw box at position %f %f\n", s->x, s->y);
}

void drawCircle( struct shape *s) 
{
    printf("draw circle at position %f %f\n", s->x, s->y);  
}


struct shape* shapeFactory(int type, int xpos, int ypos) 
{
    struct shape* ptr = 0;

    switch (type)
    {
        case 0: 
            ptr = (struct shape*) malloc(sizeof(shape));
            ptr->shapeDraw = &drawShape;
            break;
        case 1:
            ptr = (struct shape*) malloc(sizeof(box));
            ptr->shapeDraw = &drawBox;
            break;
        case 2:
            ptr = (struct shape*) malloc(sizeof(circle));
            ptr->shapeDraw = &drawCircle;
            break;
    };

    ptr->type = type;
    ptr->x =xpos;
    ptr->y = ypos;
    return ptr;
}


void shapeFree(struct shape* s) 
{
    switch (s->type)
    {
    case 0:
        free((struct shape*)(s));
        break;
    case 1:
        free((struct box*)(s));
        break;
    case 2:
        free((struct circle*)(s));
        break;
    };    
}

void draw(struct shape* s) 
{
    s->shapeDraw(s);
};

int main() 
{
    shape* s = 0;
    box* b = 0;
    circle* c = 0;

    s = shapeFactory(SHAPE_SHAPE, 10, 10);
    b = (struct box*) shapeFactory(SHAPE_BOX, 20,20);
    c = (struct circle*) shapeFactory(SHAPE_CIRCLE, 30, 30);
  
    draw((SHAPEME(s)));
    draw((SHAPEME(b)));
    draw((SHAPEME(c)));

    shapeFree((SHAPEME(s)));
    shapeFree((SHAPEME(b)));
    shapeFree((SHAPEME(c)));


    system("pause");
    return 0;
}
Что ел то - в долг, что жил то - зря.
Для избранных. ))
Секретные разработки
intmain вне форума Ответить с цитированием
Старый 12.12.2012, 23:48   #10
Abstraction
Старожил
 
Аватар для Abstraction
 
Регистрация: 25.10.2011
Сообщений: 3,178
По умолчанию

Цитата:
Я тут кое чего написал, но не пойму почему у меня нули везде когда должны быть цифры 10 20 и 30 ?
Потому что тип int, а выводите Вы их почему-то со спецификатором %f (float). Поправьте.

Цитата:
И еще вопрос, насколько я правильно освобождаю память?
free принимает произвольный указатель. Так что в данном примере можете просто вызывать free(s), а в принципе достаточно добавить указатель на метод deconstruct в структуру, который будет освобождать ресурсы объекта и вызывать для него free - опять же, без приведения типов.
Abstraction вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
ООП kiss2 Паскаль, Turbo Pascal, PascalABC.NET 0 14.06.2010 13:17
ООП VladimirVB Общие вопросы Delphi 4 18.11.2009 22:51
Паскаль ООП. Примеры программ с использованием ООП SeЯgey Помощь студентам 5 13.05.2009 21:55
ООП Andrey Gort Общие вопросы Delphi 1 22.11.2006 15:01