2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Тонкости наследования с C++
Сообщение03.08.2020, 16:27 
Заслуженный участник


31/12/15
922
Есть класс "фигура", при создании экземпляра вычисляется большой массив координат. От него наследуется класс "хитрая фигура", при создании экземпляра массив координат вычисляется по другой формуле. Я правильно понимаю, что при создании хитрой фигуры сначала срабатывает конструктор класса "фигура" и массив вычисляется два раза? Если да, то как исправить?

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 16:49 


09/05/16
138
Да, при создании экземпляра дочернего класса сначала вызывается конструктор родительского класса, этого не избежать. (извините, отвечаю без ссылок на стандарт)

Возможно, стоит наследовать оба класса от более абстрактного базового класса, содержащего общие для обоих методы? Если существование объектов базового класса хотите запретить (например, потому что без конструктора в дочерних классах такие объекты никому не нужны), можете сделать его конструктор protected:. Тогда дочерние классы будут иметь право на создание объекта (и вызов конструктора) как часть себя, а все остальные - нет.

Альтернативное решение: родительскому классу добавить специальный конструктор, который вычислений не делает, а в дочернем классе явно вызывать именно его:

Используется синтаксис C++
struct no_calculations_tag{};

class Parent {
public:
 Parent() { /* many calculations */ }
protected:
 Parent(const no_calculations_tag &) {}
public: // other methods
};

class Child : public Parent {
public:
 Child() : Parent(no_calculations_tag()) { /* child-specific calculations */ }
 // other methods
};

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 18:03 
Заслуженный участник
Аватара пользователя


01/09/13
4318
Вычислять массив в отдельной виртуальной ф-ции.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 18:10 
Заслуженный участник
Аватара пользователя


16/07/14
8355
Цюрих
Geen в сообщении #1477138 писал(а):
Вычислять массив в отдельной виртуальной ф-ции
Не сработает. Конструктор базового класса всё равно позовется, и на момент его вызова будет vtable от базового класса.
(и вообще, вызывать виртуальные функции в конструкторе нехорошо)
aitap всё правильно пишет - либо создаем отдельный конструктор, либо выносим общую часть в общий базовый класс.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 18:38 
Заслуженный участник


26/05/14
981
Если два класса различаются только в момент конструирования, то наследование не нужно. Два конструктора решат проблему.

-- 03.08.2020, 18:41 --

Geen в сообщении #1477138 писал(а):
Вычислять массив в отдельной виртуальной ф-ции.

Это хождение по краю. Виртуальные функции в конструкторах вызываются невиртуально: https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 20:18 
Заслуженный участник


31/12/15
922
Спасибо, я попробую. А если сделать конструктор с дополнительным булевым параметром (вычисляй массив / не вычисляй массив)? Из дочернего класса вызываем конструктор родителя с параметром "не вычисляй", а уж потом вызываем функцию (даже можно виртуальную), которая вычисляет? Это сработает?

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 20:23 
Заслуженный участник
Аватара пользователя


16/07/14
8355
Цюрих
Это сработает, но у пользователя снаружи будет возможность создать базовый класс без вычисления массива. Смотрите сами, является ли это осмысленным. И в целом тут ИМХО лучше отдельный конструктор. Если есть какие-то действия, которые нужны всегда, и иногда дополнительно нужно создать массив - то можно сделать конструктор, который массив не создает, и звать его из другого, который уже создает.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение03.08.2020, 20:44 
Заслуженный участник


06/07/11
5627
кран.набрать.грамота
george66
А может вам вместо наследования лучше использовать композицию? Я не знаю С++, но могу проиллюстрировать на примере java. Сейчас у вас что-то вроде такого:

Используется синтаксис Java
class Figure {  // класс "фигура"
    Coordinate[] data;  // массив координат
    public Figure() {  // конструктор
        // много вычислений для фигуры
    }
}

class TrickyFigure extends Figure {  // класс "хитрая фигура" - наследник просто "фигуры"
    public TrickyFigure Figure() {  // конструктор
        // много вычислений для хитрой фигуры
    }
}
 

А вместо этого сделать:
код: [ скачать ] [ спрятать ]
Используется синтаксис Java
interface ICalculation {
    Coordinate[] executeInitCalculations();  // интерфейс для вычислений
}

class FigureInitializator implements ICalculation {
    Coordinate[] executeInitCalculations() {
        // много вычислений для фигуры
    }
}

class TrickyFigureInitializator implements ICalculation {
    Coordinate[] executeInitCalculations() {
        // много вычислений для хитрой фигуры
    }
}

class Figure {  // класс "фигура"
    Coordinate[] data;  // массив координат
    public Figure(ICalculation initializator) {  // конструктор
        Coordinate[] := initializator.executeInitCalculations; // много вычислений для фигуры или хитрой фигуры
    }
}
 

В этом случае, в том месте, в котором вам надо использовать соответствующую фигуру, вы будете писать:
Используется синтаксис Java
// объявляем переменные нужных типов
Figure myFigure;
Figure myTrickyFigure;

// инициализируем нужным в данный момент способом:
myFigure = new Figure(new FigureInitializator());
myTrickyFigure = new Figure(new TrickyFigureInitializator());

 

В java нет множественного наследования, поэтому там используются интерфейсы. В С++ множественное наследование вроде бы есть, поэтому можно обойтись одними классами. Но это уже смотрите, как вам удобнее.
А вообще это называется "паттерн "Стратегия"", по этим ключевым словам можете нагуглить много чего еще.

-- 03.08.2020, 18:54 --

Или может вам вообще больше паттерн Фабрика подойдет?

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение04.08.2020, 00:02 
Заслуженный участник


26/05/14
981
george66, вы можете так сделать. Но почему эти два класса неравноправны? По какому принципу вы выбрали родителя и потомка? Они же равноправные братья. Если вы хотите наследование, делайте общего предка. Если не хотите, делайте два конструктора.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение04.08.2020, 00:22 
Заслуженный участник


31/12/15
922
Грубо говоря, при рисовании "хитрой фигуры" учитывается свойственный ей дополнительный параметр. А при рисовании просто фигуры - нет. Соответственно, в классе "фигура" есть функция (большая и сложная), вычисляющая координаты с учётом или без учёта дополнительного параметра. Если я создам класс "просто фигура" (не "хитрая") и тоже унаследую от "фигуры", в нём ничего своего вообще не будет.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение04.08.2020, 00:31 
Заслуженный участник
Аватара пользователя


01/09/13
4318
george66 в сообщении #1477208 писал(а):
Если я создам класс "просто фигура" (не "хитрая") и тоже унаследую от "фигуры", в нём ничего своего вообще не будет.

А разве кроме конструктора ничего нет??...

-- 04.08.2020, 00:34 --

slavav в сообщении #1477145 писал(а):
Это хождение по краю

mihaild в сообщении #1477139 писал(а):
Не сработает.

Вполне возможно - я уже давно и сознательно избегаю такого дизайна, где бы это могло понадобиться - видимо забыл детали.

 Профиль  
                  
 
 Re: Тонкости наследования с C++
Сообщение04.08.2020, 00:54 
Заслуженный участник


26/05/14
981
george66, простая и хитрая фигуры в чём-то отличаются после того как вы их создали и заполнили массивы?

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group