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


Автор: Fedor 17.6.2007, 12:25
Не нашел такой темы...

как в с++ запретить наследование класса? 
в .net эта штука, насколько я понимаю называется sealed. А как здесь?

Автор: Daevaorn 17.6.2007, 12:31
Цитата(Fedor @  17.6.2007,  13:25 Найти цитируемый пост)
А как здесь?

сделать конструкторы private. А для создания объекта написать "фабричный метод"

Автор: Fedor 17.6.2007, 12:46
Цитата(Daevaorn @  17.6.2007,  12:31 Найти цитируемый пост)
 А для создания объекта написать "фабричный метод"

типа
Код

A* A::Create()
{}

??

Добавлено через 4 минуты и 3 секунды
Хотя так не пойдет... В общем, как это фабричный метод? )

Автор: Xenon 17.6.2007, 13:07
Я понимаю так.
Код

class Foo
{
private:
    int m_var;
    Foo(int var = 0):m_var(var){}
public:
    static Foo* create_Foo(int var = 0)
    {
        return new Foo(var);
    }
};
int main(int argc, char* argv[]) 
{
    Foo* obj = Foo::create_Foo(10);
    delete obj;
    std::cin.sync();
    std::cin.get();
    return 0;
}


Добавлено через 1 минуту и 53 секунды
Ну или так:
Код

class Foo
{
private:
    int m_var;
    Foo(int var = 0):m_var(var){}
public:
    friend Foo* create_Foo(int var);
};

Foo* create_Foo(int var = 0)
{
    return new Foo(var);
}

int main(int argc, char* argv[]) 
{
    Foo* obj = create_Foo(10);
    delete obj;
    std::cin.sync();
    std::cin.get();
    return 0;
}


Автор: Feniksa 17.6.2007, 13:45
Fedor,  а какой компилятор используеш?  smile  В зависимости от компилятора, можно директивами заставить не наследовать класс... Всё зависит от компилятора (и его версии)  smile 

Автор: Damarus 17.6.2007, 14:04
Цитата(Feniksa @  17.6.2007,  13:45 Найти цитируемый пост)
В зависимости от компилятора, можно директивами заставить не наследовать класс...

 smile  smile 

Автор: Xenon 17.6.2007, 14:18
Если комилятор для C#, то можно приписать sealed?  smile 

Автор: Damarus 17.6.2007, 15:47
Цитата(Xenon @  17.6.2007,  14:18 Найти цитируемый пост)
Если комилятор для C#, то можно приписать sealed?

Ну, так не интересно. Если тема в разделе C++, то и компиляторы должны быть для С++. 

Автор: Xenon 17.6.2007, 15:48
Damarus, ну это был риторический вопрос автору идеи smile

Автор: Fin 17.6.2007, 15:56
Вопрос на засыпку: Назовите внятную и вескую причину, Зачем нужно запрешать наследование? Тем самым нарушая основной принцип ООП.

Автор: Xenon 17.6.2007, 16:14
Fin, какой принцип? Где написано, что все классы должны иметь способность к классическому наследованию?

Автор: Fin 17.6.2007, 17:23
Xenon, Открой любой учебник, где хотя бы краем упоминается Объектно Оринтированное Программирование. Там обязательно будут упоменены три кита ООП: инкапсуляция, наследование и полиморфизм.

Автор: skyboy 17.6.2007, 17:30
Fin, давай без фанатизма, а? то, что аксиоматическим началом эвклидовой геометрии является непересекаемость параллельных прямых вовсе не означает, что все прямые должны быть параллельны  smile 

Автор: Fin 17.6.2007, 17:58
Ну я так и не услышал причину? Или запретить ради запрешения smile В принципе на С++ я знаю как обойти данное закрытие наследования. Нужен только большой бубен и полчаса работы.

Автор: Xenon 17.6.2007, 18:04
Fin, открыл, ну и? Да, согласен, в ООП есть и инкапсуляция и полиморфизм и наследование ... Что, я теперь в каждом классе должен все функции помечать как virtual, приватные члены делать защищенными? А, ну тогда еще нельзя использовать friend, так как друзья - палки в колеса настоящему ООП.
Свою очередь могу посоветовать открыть Страуструпа на 23 главе "Разработка и проектирование"

Автор: archimed7592 17.6.2007, 18:31
Fedor, лучше запретить деструктор - тогда будет класс как класс, но без возможности наследования.


Fin, поверь, причины бывают... как правило архитектурные.

Добавлено через 1 минуту и 6 секунд
Цитата(archimed7592 @  17.6.2007,  18:31 Найти цитируемый пост)
лучше запретить деструктор
эээ... хотя, туплю... класс как класс не буит... smile  сорри за запутывание...

Автор: skyboy 17.6.2007, 18:33
Fin, не знаю, быть может, мой пример - ошибка проектирования...Кроме того, не знаю, возможен ли такой поворот событий в С++(пример пришел из опыта программирования на Delphi)
были у меня объекты. реально конструируемые. а потом возникла потребность скрыть конструктор и сделать фабричный метод, чтоб предотвратить создание логически одинаковых объектов. И вот занаследует человек мой класс(ещё вопрос - зачем) и в своем конструкторе сделает вызов... моего фабричного метода. И фабричный метод найдет подходящий объект и увеличит его счетчик ссылок, или не найдет и создаст новый объект, который канет в бездну... В любом случае, человек со своим наследником моего класса не получит то, чего ожидал - вызов конструктора предка для дополнительной инициализации. Можно, конечно, раскомментировать случаи использования как только можно. Но безопасней было бы запретить наследование. И, если ему(клиенту) надо будет - пусть делает композицию с моим объектом. 
В общем, как на меня, запрет наследования был бы "в кассу" если необходимо предотвратить работу с фабричными методами вместо обычных конструкторов smile
P.S. Кидайте помидоры, мне даже интересно, где ошибся при проектировании smile

Автор: MAKCim 17.6.2007, 18:34
Код

class A;

class B
{
private:
    B() {}
    friend class A;
};

// от A нельзя породить дочерний класс, т. к он должен 
// явно вызвать конструктор виртуального базового
// класса, но он - private, а friend-овость не наследуется
class A: virtual private B
{
};

Автор: Vyacheslav 19.6.2007, 12:32
Цитата(Fin @  17.6.2007,  17:58 Найти цитируемый пост)
Ну я так и не услышал причину? Или запретить ради запрешения  В принципе на С++ я знаю как обойти данное закрытие наследования. Нужен только большой бубен и полчаса работы. 

Например при реализации партерна Singleton. 
Ну и в свою очередь, Вы бы не могли продемонстрировать бубен, с помощью которого Вы сможете унаследовать класс с приватным  конструктором, не внося изменений в интерфейс класса 

Автор: MAKCim 19.6.2007, 12:34
Товарищи, чем вас не устраивает мой вариант?  smile 

Автор: Xenon 19.6.2007, 12:43
MAKCim, в принципе неплохо, но по-моему не очень очевидная реализация smile

Автор: Vyacheslav 19.6.2007, 13:04
Цитата(MAKCim @  19.6.2007,  12:34 Найти цитируемый пост)
Товарищи, чем вас не устраивает мой вариант?    

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

Автор: MAKCim 19.6.2007, 13:06
Vyacheslav, 
а если комментарии прочитать  smile 

Автор: Xenon 19.6.2007, 13:07
Vyacheslav, без виртуального наследования производные классы от A можно будет строить

Автор: Vyacheslav 19.6.2007, 13:08
Вопрос снят smile

Автор: MAKCim 19.6.2007, 13:08
Цитата(Xenon @  19.6.2007,  12:43 Найти цитируемый пост)
в принципе неплохо, но по-моему не очень очевидная реализация

зато действенная
и объекты класса A можно без напряга создавать

Автор: archimed7592 19.6.2007, 14:58
MAKCim, минус твоей реализации: оверхэд из-за виртуального наследования. Ну это так - для общей картины smile.

Автор: math64 19.6.2007, 15:00
Код

class A;    
class B    
{    
private:    
    B() {}    
    friend class A;    
};    
// от A нельзя породить дочерний класс, т. к он должен    
// явно вызвать конструктор виртуального базового    
// класса, но он - private, а friend-овость не наследуется    
class A: virtual private B    
{    
};

class C : public A {
};


Компилирется gcc без ошибок

Автор: Daevaorn 19.6.2007, 15:04
Цитата(math64 @  19.6.2007,  16:00 Найти цитируемый пост)
Компилирется gcc без ошибок 

Добавь конструкторы или явно инстанцируй C

Автор: MAKCim 19.6.2007, 17:04
Цитата(archimed7592 @  19.6.2007,  14:58 Найти цитируемый пост)
MAKCim, минус твоей реализации: оверхэд из-за виртуального наследования.

есть вариант лучше?

Автор: archimed7592 19.6.2007, 17:10
Цитата(MAKCim @  19.6.2007,  17:04 Найти цитируемый пост)
есть вариант лучше?

MAKCim, я же специально сказал:
Цитата(archimed7592 @  19.6.2007,  14:58 Найти цитируемый пост)
Ну это так - для общей картины

Можно сделать как у тебя и поиметь удобство(+) и оверхэд(-). Можно сделать иначе и поиметь неудобство(-) и скорость(+). Смотря что критичней - зависит от ситуации. Лучших решений не бывает. Бывают рациональные.

Автор: MAKCim 19.6.2007, 17:37
Цитата(archimed7592 @  19.6.2007,  17:10 Найти цитируемый пост)
Можно сделать как у тебя и поиметь удобство(+) и оверхэд(-). Можно сделать иначе и поиметь неудобство(-) и скорость(+). Смотря что критичней - зависит от ситуации. Лучших решений не бывает. Бывают рациональные. 

надо бы проверить насколько мой вариант уступает в скорости (если вообще уступает)
если использовать static функцию + new
Код

...
static A *create() {
    return new A();
}
...

то однозначно мой вариант быстрее в случае статических объектов 
Код

A a;

и немного уступает в случае динамического создания 
Код

A *a = new A();

засчет дополнительного создания объекта класса B, но класс B - пустой и при достаточной оптимизации подобъект этого класса вообще можно не создавать

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