Наследование. Вопрос
От: roman313  
Дата: 04.08.11 15:51
Оценка:
Hi,
есть такой вопрос:

Пусть есть базовый класс,
и два дочерний класса, которые наследуются от базового.

Например:

Base
|
---------------------
| |
Derived1 Derived2

И скажем, я задаю класс Derived3, который должен наследоваться только
от Derived1 или только от Derived2.

В общем-то вопрос заключается в том, можно-ли средствами языка С++
как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить
наследовать только от одного класса, Derived1 или Derived2) ?
Re: Наследование. Вопрос
От: LaptevVV Россия  
Дата: 04.08.11 16:00
Оценка: 16 (3)
Здравствуйте, roman313, Вы писали:

R>Hi,

R>есть такой вопрос:

R>Пусть есть базовый класс,

R>и два дочерний класса, которые наследуются от базового.

R>Например:


R> Base

R> |
R> ---------------------
R> | |
R>Derived1 Derived2

R>И скажем, я задаю класс Derived3, который должен наследоваться только

R>от Derived1 или только от Derived2.

R>В общем-то вопрос заключается в том, можно-ли средствами языка С++

R>как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить
R>наследовать только от одного класса, Derived1 или Derived2) ?
Специальной конструкции запрета в языке нет. Но народ изощрялся и придумал "финальный" класс. Посмотри — может поможет.

Виртуальное наследование позволяет нам запретить наследование от нашего класса. О том, что это не просто интересная «фишка», а реально необходимая возможность, говорит тот факт, в Java введено специальное ключевое слово final. Если класс объявлен как final, то пользователь не сможет от него наследовать. Класс String в библиотеке классов Java объявлен как финальный.

В С++ нет специальных ключевых слов, запрещающих наследование, поэтому объявление класса «финальным» основано на управлении доступом к специальным функциям класса: конструкторам и деструктору. Например, если объявить в базовом классе закрытым деструктор, то будет невозможно объявить переменную-объект ни базового класса, ни производного класса, например
class OnlyDynamic
{ ~OnlyDynamic();
    public: 
// …
};
class Derived: public OnlyDynamic
{ };


Наследование формально не запрещается (хотя Visual C++.NET 2003 выдает предупреждение), однако попытки объявить переменную

Derived Object;                // ошибка!


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

Derived *p = new Derived;
delete p;


Как пишет Б.Страуструп в [43], Эндрю Кениг обнаружил, что можно «запретить» наследование (а фактически — создание объектов класса-наследника), используя виртуальное наследование. Простейший пример выглядит так (листинг 12.7):

Листинг 12.7. Финальный класс
class Lock                                // «запирающий» класс
{ Lock();
  Lock(const Lock&);
  friend class Usable;
public:
};
class Usable: public virtual Lock        // «финальный» класс
{ public:
  Usable() { cout << "Usable!"; }
};
class Derived: public Usable {};        // формально не запрещено


В этом случае мы имеем «внутреннюю» иерархию из двух классов:
 запирающий класс — виртуальная база, у которого конструкторы являются приватными;
 виртуальный наследник — финальный класс, от которого нельзя наследовать.
Хотя формально наследование не запрещено, попытки создать объект класса Derived оканчиваются неудачей на этапе трансляции.

Usable u;                                // нет ошибки
Derived d;                                // ошибка трансляции
Derived *pd = new Derived;                // ошибка трансляции


Для объектов типа Derived выдается сообщение об отсутствии доступа к приватным конструкторам класса Lock.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Наследование. Вопрос
От: roman313  
Дата: 04.08.11 16:09
Оценка:
Спасибо, но тут немного случай другой —

Базовый класс Base. От него наследуются D1 и D2.

Я могу создавать классы которые наследуются или только от D1 или только от D2.
Наследование обоих D1 и D2 необходимо запретить.
Re[3]: Наследование. Вопрос
От: LaptevVV Россия  
Дата: 04.08.11 16:17
Оценка:
Здравствуйте, roman313, Вы писали:

R>Спасибо, но тут немного случай другой —


R>Базовый класс Base. От него наследуются D1 и D2.


R>Я могу создавать классы которые наследуются или только от D1 или только от D2.

R>Наследование обоих D1 и D2 необходимо запретить.
Ну дык я пример привел, чтоб ты покопался. Возможно, по аналогии можно будет чего-нить сварганить.
Например, если в кажом классе определять некую сущность, а в наследниках проверять, одна одна или ее много.
Возможно, с шаблонами удастся решить проблему. См. определение типа на этапе компиляции ака Джосаттис-Ваедевурд IsClass
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Наследование. Вопрос
От: roman313  
Дата: 04.08.11 16:20
Оценка:
спасибо, подумаю
Re[3]: Наследование. Вопрос
От: dilmah США  
Дата: 04.08.11 16:22
Оценка:
R>Базовый класс Base. От него наследуются D1 и D2.
R>Я могу создавать классы которые наследуются или только от D1 или только от D2.
R>Наследование обоих D1 и D2 необходимо запретить.

можно сделать это в рантайме -- в базовом классе сделать статический мэп, в который записывать пары (this, dynamic_cast<void*>(this))
Если окажется что есть 2 разных this базового класса у которых одинаковый dynamic_cast<void*>(this) то значит нарушено твое условие.

Эту проверку можно оптимизировать видимо, чтобы только при первых созданиях нужно было что-то запоминать.
Re[2]: Наследование. Вопрос
От: Abyx Россия  
Дата: 04.08.11 16:27
Оценка: 3 (1)
Здравствуйте, LaptevVV, Вы писали:

[...]

ссылочку на оригинал хорошо бы дать
In Zen We Trust
Re[3]: Наследование. Вопрос
От: roman313  
Дата: 04.08.11 16:36
Оценка:
- оригинал большой,
это моя GUI-библиотека.

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

Есть базовый класс скажем, CwindowBase, от него наследуются
два класса: CDialog->CWindowBase (класс для работы с диалогами)
и CWindow->CWindowBase (класс для работы с простыми окнами).

От CWindow могут наследоваться классы элементов управления.

Просто самому надо сделать так, чтобы я не смог наследовать сразу оба класса — CWindow и CDialog.

В общем интересная задача.

Думал, что есть какие-либо #pragma Microsoft,
но вроде нет ничего подобного.


Ладно, сам разберусь постепенно.


Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, LaptevVV, Вы писали:


A>[...]


A>ссылочку на оригинал хорошо бы дать
Re[4]: Наследование. Вопрос
От: roman313  
Дата: 04.08.11 16:36
Оценка:
- в run-time сработает,
но способ для меня не подходит.
Re[3]: Наследование. Вопрос
От: LaptevVV Россия  
Дата: 04.08.11 17:50
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, LaptevVV, Вы писали:


A>[...]


A>ссылочку на оригинал хорошо бы дать

Если вы о [43], то это "Дизайн и эволюция С++".
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Наследование. Вопрос
От: Abyx Россия  
Дата: 04.08.11 18:01
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Abyx, Вы писали:


A>>Здравствуйте, LaptevVV, Вы писали:


A>>[...]


A>>ссылочку на оригинал хорошо бы дать

LVV>Если вы о [43], то это "Дизайн и эволюция С++".

я о всем тексте в вашем посте
In Zen We Trust
Re[5]: Наследование. Вопрос
От: LaptevVV Россия  
Дата: 04.08.11 18:05
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, LaptevVV, Вы писали:


LVV>>Здравствуйте, Abyx, Вы писали:


A>>>Здравствуйте, LaptevVV, Вы писали:


A>>>[...]


A>>>ссылочку на оригинал хорошо бы дать

LVV>>Если вы о [43], то это "Дизайн и эволюция С++".

A>я о всем тексте в вашем посте

Текст, кроме примера я сам написал. Подглядывал у Страуструпа — см ссылку.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Наследование. Вопрос
От: Кодёнок  
Дата: 05.08.11 05:39
Оценка:
Здравствуйте, roman313, Вы писали:

R>В общем-то вопрос заключается в том, можно-ли средствами языка С++

R>как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить
R>наследовать только от одного класса, Derived1 или Derived2) ?

Можно сделать конструкцию для compile-time проверки, унаследован ли класс от другого. Но пользователям придется вручную вставлять ее в код.

С другой стороны, если у тебя есть какие-то шаблонные методы, в которые будут передаваться типы-наследники, можно вставить эту проверку в них
Re[2]: Наследование. Вопрос
От: Sir-G  
Дата: 05.08.11 05:44
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>вызывают ошибку компиляции. Однако такое определение базового класса не мешает нам создавать наследника в динамической памяти, например

LVV>
LVV>Derived *p = new Derived;
LVV>delete p;
LVV>

Мешает, проверил на 2008 студии. =)

LVV>Как пишет Б.Страуструп в [43], Эндрю Кениг обнаружил, что можно «запретить» наследование (а фактически — создание объектов класса-наследника), используя виртуальное наследование. Простейший пример выглядит так (листинг 12.7):

А это имхо, какой-то изврат. Чтобы «запретить» наследование, проще всего все конструкторы сделать приватными и сделать статические функции создания типа CreateInstance( params ).
Re: Наследование. Вопрос
От: jazzer Россия Skype: enerjazzer
Дата: 05.08.11 05:52
Оценка: 1 (1)
Здравствуйте, roman313, Вы писали:

R>В общем-то вопрос заключается в том, можно-ли средствами языка С++

R>как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить
R>наследовать только от одного класса, Derived1 или Derived2) ?
Тебе это зачем?
Просто чтоб объекты нельзя было создать?
Или объекты создавать можно, а ошибка возникнет только при попытке засунуть такой объект в определенную функцию, которая при таком множественном наследовании будет работать неправильно?
Если так, то можно сделать шаблонный переходник для этой функции, у которой внутри будет
int f(Base&); // принимает потомков по ссылке, её надо защитить

// одноименная функция-перехватчик, ее тело не компилируется
// она будет доступна для поиска только если класс отнаследован от обоих Derived1 и Derived2
template<class T>
typename
  boost::enable_if_c< boost::is_base_of< Derived1, T >::value
                   && boost::is_base_of< Derived2, T >::value >::type
f(const T& t)
{
  // READ THIS IF YOUR COMPILATION BREAKS HERE
  // T shouldn't derive from both Derived1 and Derived2
  BOOST_STATIC_ASSERT(( false ));
}
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.