имеет ли смысл наследовать в частном порядке от абстрактного (чисто виртуального) класса? - PullRequest
4 голосов
/ 10 июля 2011

предположим, что эта конструкция

struct InterfaceForFoo
{
    virtual void GetItDone() = 0;
};


class APoliticallyCorrectImplementationOfFooRelatedThings : private InterfaceForFoo
{

  public:
    void GetItDone() { /*do the thing already*/ };   
};

Теперь мне интересно, есть ли какие-либо полезные сценарии наследования от интерфейса таким способом.

Ответы [ 5 ]

5 голосов
/ 10 июля 2011

Да, все здесь говорят "нет".Я говорю «да, это имеет смысл».

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
1 голос
/ 11 июля 2011

Вопрос в том, почему важно, чтобы в базовом классе были только чисто виртуальные методы?

Две вещи почти не связаны. Приватный означает, что это деталь реализации вашего класса, а не часть открытого интерфейса, но вы можете захотеть реализовать интерфейс как деталь реализации. Предположим, что вы пишете класс, и что вы решили реализовать функциональность с помощью библиотеки, которая требует от вас реализации интерфейса. Это деталь реализации, нет необходимости делать наследование общедоступным только потому, что интерфейс имеет только чисто виртуальные функции.

1 голос
/ 10 июля 2011

В объектно-ориентированном аспекте нет варианта использования для такого private наследования для абстрактного class.

Однако, если вы хотите указать, что ваш ребенок class должен получить определенные методы, выможете использовать это.Например:

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()
};

Так что это просто помогает поддерживать дисциплину личного кодирования .Сообщение с этим примером заключается в том, что наследование предназначено не только для объектно-ориентированной цели.Вы даже можете использовать наследование для остановки цепочки наследования (что-то вроде Java final).

0 голосов
/ 10 июля 2011

А?Нет, в этом нет абсолютно никакого смысла, поскольку вы предоставляете интерфейс, потому что вы хотите, чтобы другие использовали ваш класс через этот интерфейс .Как это будет работать, если они не знают, что вы реализуете это?

#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*.

0 голосов
/ 10 июля 2011

Не совсем.Если вам нужна функция, вы реализуете ее.Нет смысла навязывать функцию, которая не может использоваться другими классами.

Почему вы наследуете конфиденциально от интерфейса, я не знаю;этот тип побеждает назначение интерфейсов.

Если это не интерфейс, а класс, то имеет смысл:

class A {
    virtual void foo() = 0;

    void bar() {
        foo();
    }
};

class B : private A {
    virtual void foo() {

    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...