имеет ли смысл наследовать частным образом от абстрактного (чисто виртуального) класса?
Предположим, что эта конструкция
struct InterfaceForFoo
{
virtual void GetItDone() = 0;
};
class APoliticallyCorrectImplementationOfFooRelatedThings : private InterfaceForFoo
{
public:
void GetItDone() { /*do the thing already*/ };
};
Теперь мне интересно, есть ли у наследования приватно от интерфейса таким образом какие-либо полезные сценарии.
5 ответов:
Ха, все здесь говорят "нет". Я говорю: "Да, это имеет смысл."
Создание наследованияclass VirtualBase { public: virtual void vmethod() = 0; // If "global" is an instance of Concrete, then you can still access // VirtualBase's public members, even though they're private members for Concrete static VirtualBase *global; }; // This can also access all of VirtualBase's public members, // even if an instance of Concrete is passed in, void someComplicatedFunction(VirtualBase &obj, ...); class Concrete : private VirtualBase { private: virtual void vmethod(); public: void cmethod() { // This assignment can only be done by Concrete or friends of Concrete VirtualBase::global = this; // This can also only be done by Concrete and friends someComplicatedFunction(*this); } };
private
не означает, что вы не можете получить доступ к членамVirtualBase
из-за пределов класса, это означает только, что вы не можете получить доступ к этим членам через ссылку наConcrete
. ОднакоConcrete
и его друзья могут приводить экземплярыConcrete
кVirtualBase
, и тогда любой может получить доступ к открытым членам. Просто,Concrete *obj = new Concrete; obj->vmethod(); // error, vmethod is private VirtualBase *obj = VirtualBase::global; obj->vmethod(); // OK, even if "obj" is really an instance of Concrete
В объектно-ориентированном аспекте нет случая использования такого
private
наследования для абстрактногоclass
.Однако, если вы хотите поручить, чтобы ваш ребенок
class
должен получить определенные методы, то вы можете использовать это. Например:Таким образом, это просто помогает поддерживать дисциплину личного кодирования . Сообщение с этим примером заключается в том, что наследование не просто предназначено для объектно-ориентированной цели. Вы даже можете использовать наследование для остановки цепочки наследования (что-то вроде Java final).struct implement_size { virtual size_t size () = 0; }; class MyVector : private implement_size { public: size_t size () { ... } // mandatory to implement size() } class MyString : private implement_size { public: size_t size () { ... } // mandatory to implement size() };
Вопрос в том, почему это должно иметь значение, что базовый класс имеет только чистые виртуальные методы?
Эти две вещи почти не связаны между собой. Private означает, что это деталь реализации вашего класса, а не часть открытого интерфейса, но вы можете захотеть реализовать интерфейс как деталь реализации. Считайте, что вы пишете класс, и что вы решили реализовать функциональность с помощью библиотеки, которая требует, чтобы вы реализовали интерфейс. Это и есть реализация подробно, нет необходимости делать наследование открытым только потому, что интерфейс имеет только чисто виртуальные функции.
А? Нет, это абсолютно бессмысленно, поскольку причина, по которой вы предоставляете интерфейс, заключается в том, что вы хотите, чтобы другие использовали ваш класс через этот интерфейс. Как это будет работать, если они не знают, что вы его реализуете?
Приведенный выше пример не работает, потому что внешний мир не знает, что#include <vector> class Fooable{ public: virtual void foo() = 0; }; class DoesFoo : private Fooable { void foo(); }; int main(){ std::vector<Fooable*> vf; vf.push_back(new DoesFoo()); // nope, doesn't work vf[0]->foo(); }
DoesFoo
являетсяFooable
, поэтому вы не можетеnew
создать его экземпляр и назначить егоFooable*
.
Не совсем. Если вам нужна функция, Вы ее реализуете. Нет смысла форсировать функцию, которая не может быть использована другими классами.
Я не знаю, почему вы унаследовали бы в частном порядке от интерфейса; это разрушает цель интерфейсов.
Если это не интерфейс, а класс, то это имеет смысл:
class A { virtual void foo() = 0; void bar() { foo(); } }; class B : private A { virtual void foo() { } };