Здравствуйте, 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.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, roman313, Вы писали:
R>В общем-то вопрос заключается в том, можно-ли средствами языка С++ R>как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить R>наследовать только от одного класса, Derived1 или Derived2) ?
Тебе это зачем?
Просто чтоб объекты нельзя было создать?
Или объекты создавать можно, а ошибка возникнет только при попытке засунуть такой объект в определенную функцию, которая при таком множественном наследовании будет работать неправильно?
Если так, то можно сделать шаблонный переходник для этой функции, у которой внутри будет
int f(Base&); // принимает потомков по ссылке, её надо защитить
// одноименная функция-перехватчик, ее тело не компилируется
// она будет доступна для поиска только если класс отнаследован от обоих Derived1 и Derived2template<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 ));
}
Пусть есть базовый класс,
и два дочерний класса, которые наследуются от базового.
Например:
Base
|
---------------------
| |
Derived1 Derived2
И скажем, я задаю класс Derived3, который должен наследоваться только
от Derived1 или только от Derived2.
В общем-то вопрос заключается в том, можно-ли средствами языка С++
как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить
наследовать только от одного класса, Derived1 или Derived2) ?
Здравствуйте, roman313, Вы писали:
R>Спасибо, но тут немного случай другой —
R>Базовый класс Base. От него наследуются D1 и D2.
R>Я могу создавать классы которые наследуются или только от D1 или только от D2. R>Наследование обоих D1 и D2 необходимо запретить.
Ну дык я пример привел, чтоб ты покопался. Возможно, по аналогии можно будет чего-нить сварганить.
Например, если в кажом классе определять некую сущность, а в наследниках проверять, одна одна или ее много.
Возможно, с шаблонами удастся решить проблему. См. определение типа на этапе компиляции ака Джосаттис-Ваедевурд IsClass
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
R>Базовый класс Base. От него наследуются D1 и D2. R>Я могу создавать классы которые наследуются или только от D1 или только от D2. R>Наследование обоих D1 и D2 необходимо запретить.
можно сделать это в рантайме -- в базовом классе сделать статический мэп, в который записывать пары (this, dynamic_cast<void*>(this))
Если окажется что есть 2 разных this базового класса у которых одинаковый dynamic_cast<void*>(this) то значит нарушено твое условие.
Эту проверку можно оптимизировать видимо, чтобы только при первых созданиях нужно было что-то запоминать.
Все нормально работает, диалоги, окна, эл-ты управления.
Есть базовый класс скажем, CwindowBase, от него наследуются
два класса: CDialog->CWindowBase (класс для работы с диалогами)
и CWindow->CWindowBase (класс для работы с простыми окнами).
От CWindow могут наследоваться классы элементов управления.
Просто самому надо сделать так, чтобы я не смог наследовать сразу оба класса — CWindow и CDialog.
В общем интересная задача.
Думал, что есть какие-либо #pragma Microsoft,
но вроде нет ничего подобного.
Ладно, сам разберусь постепенно.
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, LaptevVV, Вы писали:
A>[...]
A>ссылочку на оригинал хорошо бы дать
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, LaptevVV, Вы писали:
A>[...]
A>ссылочку на оригинал хорошо бы дать
Если вы о [43], то это "Дизайн и эволюция С++".
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, Abyx, Вы писали:
A>>Здравствуйте, LaptevVV, Вы писали:
A>>[...]
A>>ссылочку на оригинал хорошо бы дать LVV>Если вы о [43], то это "Дизайн и эволюция С++".
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, LaptevVV, Вы писали:
LVV>>Здравствуйте, Abyx, Вы писали:
A>>>Здравствуйте, LaptevVV, Вы писали:
A>>>[...]
A>>>ссылочку на оригинал хорошо бы дать LVV>>Если вы о [43], то это "Дизайн и эволюция С++".
A>я о всем тексте в вашем посте
Текст, кроме примера я сам написал. Подглядывал у Страуструпа — см ссылку.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, roman313, Вы писали:
R>В общем-то вопрос заключается в том, можно-ли средствами языка С++ R>как-то запретить классу Derived3 наследовать оба класса Derived1 и Derived2 (разрешить R>наследовать только от одного класса, Derived1 или Derived2) ?
Можно сделать конструкцию для compile-time проверки, унаследован ли класс от другого. Но пользователям придется вручную вставлять ее в код.
С другой стороны, если у тебя есть какие-то шаблонные методы, в которые будут передаваться типы-наследники, можно вставить эту проверку в них
Здравствуйте, LaptevVV, Вы писали:
LVV>вызывают ошибку компиляции. Однако такое определение базового класса не мешает нам создавать наследника в динамической памяти, например LVV>
LVV>Derived *p = new Derived;
LVV>delete p;
LVV>
Мешает, проверил на 2008 студии. =)
LVV>Как пишет Б.Страуструп в [43], Эндрю Кениг обнаружил, что можно «запретить» наследование (а фактически — создание объектов класса-наследника), используя виртуальное наследование. Простейший пример выглядит так (листинг 12.7):
А это имхо, какой-то изврат. Чтобы «запретить» наследование, проще всего все конструкторы сделать приватными и сделать статические функции создания типа CreateInstance( params ).