C ++ частное наследование и статические члены / типы - PullRequest
6 голосов
/ 15 июня 2010

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

class Base
{
public:
    enum Enum
    {
        value
    };
};

class Middle : private Base
{ 
};

class Child : public Middle
{
public:
    void Method()
    {
        Base::Enum e = Base::value; // doesn't compile BAD!     
        Base* base = this; // doesn't compile GOOD!
    }
};

Я пробовал это как в VS2008 (необходимая версия), так и в VS2010, ни одна из них не работает.

Кто-нибудь может подумать об обходном пути? Или другой подход к остановке конверсии?

Также меня интересует поведение, это просто побочный эффект от реализации компилятора, или это задумано? Если по замыслу, то почему? Я всегда думал, что частное наследование означает, что никто не знает, что Мидл наследует от Базы. Тем не менее, демонстрируемое поведение подразумевает, что частное наследование означает гораздо больше, фактически, у Child меньше доступа к Base, чем к любому пространству имен, не входящему в иерархию классов!

Ответы [ 2 ]

6 голосов
/ 15 июня 2010

Вы должны иметь возможность получить доступ к Base::Enum, полностью указав его:

class Child : public Middle
{
public:
    void Method()
    {
        ::Base::Enum e = ::Base::value;
    }
};

Это поведение, определенное языком (C ++ 03 §11.2 / 3):

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

За этим следует расширенный пример, который по сути похож на ваш пример кода.

Однако, похоже, что ни Visual C ++ 2008, ни Visual C ++ 2010 правильно не реализуют это, поэтому, хотя вы можете использовать тип ::Base::Enum, вы все равно не сможете получить доступ к ::Base::value.(На самом деле, Visual C ++, похоже, многое понял неправильно, так как неправильно позволяет использовать не полностью квалифицированную Base::Enum).

Чтобы «обойти» проблему, вы можете добавить с помощью объявлений класс Middle:

class Middle : private Base
{ 
protected:

    using Base::Enum;
    using Base::value;
};

Это не позволит вам использовать Base::Enum или Base::value вваш Child класс, но он позволит вам использовать Enum и value или Middle::Enum и Middle::value.

1 голос
/ 16 июня 2010

У меня только один вопрос: зачем вам вообще частное наследство?

Наследование - это, по моему мнению, довольно сломанная концепция, потому что оно нарушает принцип Единой ответственности:

  • вы наследуете интерфейс
  • вы наследуете реализацию

К сожалению, наследование требуется для полиморфизма в объектно-ориентированном коде, поэтому вы не можете от него уклониться.

Но здесь вы явно не хотите использовать полиморфизм, поэтому я задаюсь вопросом, зачем вообще использовать наследование, поскольку это его единственное интересное использование (imo).

Вместо этого в C ++ вы можете использовать:

  • Композиция, для повторного использования кода
  • Свободные функции (определенные в их собственном пространстве имен)
  • using, typedef и т. Д. Для извлечения объектов изза пределами класса

Ваш пример здесь ограничен, но я тоже перенесу свои перечисления в struct, чтобы предотвратить загрязнение пространства имен тысячами символов (и потому что struct можно использовать в качестве шаблона parameters, где пространства имен не могут).

struct MyEnum
{
  enum type
  {
    value
  };
};

class Child
{
public:
  typedef MyEnum::type Enum;

  Child(Enum e = MyEnum::value);

private:
};

Я не вижу ничего плохого в определении имени, вместо этого я чувствую, что это облегчает чтение снова, так как вы знаете, о каком перечислении мы говорим ...

Действительно, private наследование лучше избегать (и обычно заменяется на Composition).Единственный допустимый случай (imo) - для оптимизации пустых баз ... и, честно говоря, это не часто вам нужно (как обычно с оптимизацией).

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