Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Зачем людям наследование?


Автор: Tobuk 22.12.2009, 16:05
Код

class void_point
{
};

class point1d : public void_point
{
public:
    int x;
};

class point2d : public point1d
{
public:
    int y;
};


В чем преимущество данного подхода? (с наследованием)
Почему бы просто не объявить point1d и point2d ???
Ни как не пойму.

Автор: mes 22.12.2009, 16:53
Цитата(Tobuk @  22.12.2009,  15:05 Найти цитируемый пост)
Почему бы просто не объявить point1d и point2d ??? Ни как не пойму. 

Вас интересует наследование в контексте текущего примера ? тут скорей всего, судя по приведенному фрагменту, автор переборщил..
или наследование как таковое ? - тогда Вы нехороший пример выбрали для разбора и анализа..

Автор: bsa 22.12.2009, 17:00
Tobuk, наиболее красивые примеры наследования получаются из оконных компонентов. Например, компонент Widget никак не отображается, но при этом у него есть свойства, задающие его размеры и положение. Его наследует компонент Button, который уже имеет собственное изображение и реакцию на клики и пр... Так же его наследует компонент TextEdit, который умеет отображать текст... и так далее

Автор: Tobuk 22.12.2009, 17:31
Меня интересует зачем пишут ТАК:

Код
class A{
virtual void ATAATTAA() = 0;
//и еще 100 таких
};


далее
Код

class A_impl : public A
{
     virtual void AATAATTA();
//все те же функции и еще немного переменных.
};

Кроме этих двух классов ничего больше нет.
Вот вопрос. Зачем нужен класс A?
Это реальный пример из HGE

Автор: Lazin 22.12.2009, 17:36
Цитата(Tobuk @  22.12.2009,  17:31 Найти цитируемый пост)
Зачем нужен класс A?

это интерфейс

Автор: Alca 22.12.2009, 17:44
Цитата

Код

virtual void ATAATTAA() = 0;


Чтобы в каждом производном класса могла быть своя реализация ATAATTAA().

Автор: Tobuk 22.12.2009, 17:48
Цитата(Alca @  22.12.2009,  17:44 Найти цитируемый пост)
Чтобы в каждом производном класса могла быть своя реализация ATAATTAA().

спс, но книги по С++ я читал.

я говорю про реальный проект. HGE
Там есть только 1 класс и 1 "интерфейс".
Так какие другие?

Чем удобен интерфейс? Не пойму.


Автор: Alca 22.12.2009, 17:55
http://ru.wikipedia.org/wiki/Интерфейс_(объектно-ориентированное_программирование)

Добавлено @ 18:01
Цитата

Так какие другие?

Возможно, на будущее

Автор: baldina 22.12.2009, 18:02
Есть несколько аспектов, связанных с наследованием. 
1. Скорость и качество разработки. Использование наследования уменьшает необходимость повторного кодирования и, вследствие, число возможных ошибок.
Код

class ColorPoint : public Point 
{
   int color;
   ...
};

В этом классе мы добавляем функционал для работы с цветом. Прочий функционал, общий для всех точек - создание точки, рисование, математика, трансформация и т.д., просто используем. 

2. Полиморфизм (в С++ это использование виртуальных функций; неотделимо от наследования) позволяет строить изящные и эффективные архитектурные решения, использующие динамическое определение типа во время исполнения для вызова соответствующего метода (функции). Типичный пример - отображение элементов управления (виджетов):
Код

Widget* widgets[];
for (int i=0; i < num; ++i)
  widgets[i]->paint ();

Этот простой код будет рисовать кнопки, окна, поля ввода и проч., в зависимости от того на какие конкретные объекты указывают указатели в widgets. Для этого метод paint() должен быть объявлен виртуальным в базовом классе.

3. Объектный подход, использующий декомпозицию типов и объектов. Механизм наследования помогает выражать этот подход естественным образом, т.е. встроенными средствами языка. Декомпозиция - важнейший метод инженерии, в т.ч. программной, упрощающий анализ и проектирование и улучшающий качество решения за счет уменьшения связей между компонентами.
Код

class DaytimeTimer {...}; // класс для работы со временем: создать, получить/установить время, отреагировать на изменение времени через заданный интервал и т.п.
class Widget {...}; // класс компонент интерфейса пользователя
class Clock : public Widget, public DaytimeTimer {...}; // Окно-часы

Мы раздельно разрабатываем виджет и таймер. таймер ничего не знает про виджет и наоборот.

Про интерфейс, абстрактные классы и чистые виртуальные функции.
класс, имеющий чистую виртуальную функцию (=0)
Код

virtual void ATAATTAA() = 0;

называется абстрактным. Например, в примерах выше абстрактным может быть класс Widget:
Код

class Widget {
  virtual void paint() = 0;
};

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

Добавлено через 7 минут и 26 секунд
Цитата

я говорю про реальный проект. HGE
Там есть только 1 класс и 1 "интерфейс".


Разработчики старались создать расширяемую архитектуру. Что бы при добавлении функционала не переписывать половину заново, а просто добавить необходимое. Есть код, который использует указатель на объект class A. На самом деле указатель указывает на impl_A. Когда решат сделать impl2_A, то код, использующий указатели на А изменять не придется. Его даже перекомпилировать не нужно smile

Автор: Tobuk 22.12.2009, 18:16
baldina
о.О

Значит если я определю интерфейсные классы A, B и C. Отнаследую от них несколько нормальных классов с реализацией.
Потом создам класс G
Код

class G
{
    void Init();
    A *a;
    B *b;
    C *c;
};

То я смогу использовать все красиво так:
Код

G *g;
g = new G;

G->A->MakeIt();


Это нормальный подход?

Автор: GoldFinch 22.12.2009, 19:01
в HGE вообще страшный код, я тоже думаю что динамический полиморфизм там совсем не нужен

Автор: baldina 22.12.2009, 19:01
не
Код

G->A->MakeIt();

а
Код

G->a->MakeIt();

Конечно! Более чем нормальный  smile 

Пример:
Код

// самолет
class Plane {
  // предельная дальность полета
  virtual double getDistance () const = 0;
};
// маршрут
class Fly {
  Plane *plane;
  public:
    Fly (Plane *p) : plane (p) {}
    // предельная дальность маршрута (туда/обратно)
    double get_max_distance () const { return plane->getDistance() / 2; }
};

class Tu134 : public Plane {...};
class Boeng737 : public Plane {...};

Tu134 plane1;
Boeng737 plane2;

Fly f1 (&plane1);
Fly f2 (&plane2);

f1.get_max_distance (); // вызывается getDistance(), определенная для Tu134 
f2.get_max_distance (); // вызывается getDistance(), определенная для Boeng737 

Автор: Tobuk 22.12.2009, 19:16
baldina
Тогда еще вопрос.
Если от класса window отнаследовать классы window_windows и window_linux(один будет всегда в ифндефах некомпилирущийся), то это нормально?
Я так однажды сделал. Хорошо получилось(код читаемый без всяких ифндефак в каждой строчке), но мне сказали, что так ни кто не делает и нужно написать все в одном файле и нашпиговать все ифндефами. Я послушался, но получилось месиво, а не код. Какой же вариант правильный?

Автор: GoldFinch 22.12.2009, 19:23
а #ifdef зачем?

как максимум
Код

#if defined(WIN)
   typedef window_windows window_t;
#elif defined(LINUX)
   typedef window_linux window_t;
#endif

Автор: baldina 22.12.2009, 19:24
имхо твой вариант был лучше. гораздее причем smile
еще можно подключать/отключать на уровне сборки проекта (makefile)

Добавлено через 58 секунд
Цитата

а #ifdef зачем?

помимо typedef видимо желательно вообще исключить из компиляции ненужный код

Автор: bsa 22.12.2009, 21:05
Tobuk, того кто это сказал больше не слушай, он в общем не прав. Хотя он прав с точки зрения производительности. Поэтому, в каждом конкретном случае стоит использовать свои методы. Например, можно использовать http://insidecpp.ru/patterns/pimpl_idiom/, можно использовать технологию, про которую написали выше GoldFinch и baldina. А вот кучу #ifdef/#endif лучше не использовать.
Как вариант, я для себя возможным представляю только небольшие вставки на пару строчек, если их очень мало.

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