C ++ подклассификатор доступа модификатор? - PullRequest
12 голосов
/ 22 января 2011

Я новичок в C ++, и у меня многолетний опыт работы с ОО-языками, такими как C / C # / Objective-C. Сейчас я изучаю C ++.

Я видел этот код C ++:

    class World : public State
    {
    };

Кажется, класс World публично наследует класс State. Публичный подкласс? Это трудно понять.

Какова концепция этой функции? И когда это полезно или необходимо?

Ответы [ 4 ]

17 голосов
/ 22 января 2011

Потребность в ключевом слове public есть только для классов, определенных с ключевым словом class, модификатор доступа по умолчанию (для всего - членов данных, функций-членов и базовых классов) равен private. Так

class World : State {};

совпадает с:

class World : private State {};

и это, вероятно, не то, что вы хотите - это означает, что базовый класс доступен только внутри класса World. Аутсайдеры "не знают", что наследство там вообще.

Для классов, определенных с ключевым словом struct, модификатором доступа по умолчанию является public, поэтому вы могли бы написать:

struct World : State {};

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

Что касается того, почему C ++ имеет частное наследование в первую очередь: для большинства целей частное наследование является формой композиции. Нормальный состав:

class World {
    State state;
  public:
    void foo() {
        state.bar();
        state.baz();
        and so on
    }
};

То есть класс World знает, что он реализован с использованием State, а внешний мир не знает, как реализован World.

против

class World : private State {
  public:
    void foo() {
        bar();
        baz();
        and so on
    }
};

То есть класс World знает, что он реализован, когда является государством, а внешний мир не знает, как он реализован. Но вы можете выборочно раскрыть части интерфейса State, например, поместив using State::bar; в публичную часть определения World. Эффект такой, как если бы вы кропотливо написали функцию (или несколько перегрузок) в World, каждая из которых делегирует одну и ту же функцию в State.

Однако, кроме того, чтобы избегать ввода, одним из распространенных применений частного наследования является случай, когда класс State пуст, то есть не имеет элементов данных. Тогда, если он является членом World, он должен занимать некоторое пространство (по общему признанию, в зависимости от компоновки объекта это может быть пространство, которое в противном случае будет просто заполнением, поэтому это не обязательно увеличивает размер World), но тогда это базовый класс, тогда появляется вещь, называемая «оптимизация пустого базового класса», и она может быть нулевого размера. Если вы создаете много объектов, это может иметь значение. Частное наследование позволяет оптимизировать, но внешний мир не выведет отношения «есть», потому что не видит наследство.

Это довольно хорошая разница - если сомневаетесь, просто используйте явную композицию. Введение наследования для сохранения типирования очень хорошо, пока оно не приведет к неожиданным последствиям.

4 голосов
/ 22 января 2011

В случае

class World: private State
{
};

личное наследование означает, что все public и protected члены State будут наследоваться World и станут private. Это печатей State внутри World. Ни один класс, унаследованный от World, не сможет получить доступ к любым функциям State.

3 голосов
/ 22 января 2011

Что заставляет вас думать, что это личное? Здесь говорится, что публика публична, а это означает, что она является публичным подклассом.

Кроме того, частное и защищенное наследование аналогично общему наследованию, за исключением того, что все переменные-члены являются функциями, наследуемыми по крайней мере с частной или защищенной доступностью. Например, если бы State имела открытую функцию-член 'foo ()', она была бы закрытой в 'World'.

Это редко используется на практике, но у него есть цель. Наиболее распространенное использование, которое я видел, - это композиция через наследование. то есть вы хотите иметь отношение «имеет», а не «есть» (которое вы обычно получаете с публичным наследованием). Частно наследуя класс, вы получаете все его переменные и методы, но не выставляете их внешнему миру.

Одним из преимуществ использования частного наследования для композиции является пустая оптимизация базового класса (EBCO). Используя обычную композицию, наличие объекта-члена пустого класса будет по-прежнему использовать как минимум 1 байт, поскольку все переменные должны иметь уникальный адрес. Если вы унаследовали объект, из которого хотите составить данные, это неприменимо, и вы не потеряете память.

1010 *, например *

class Empty { };

class Foo
{
    int foo;
    Empty e;
};

class Bar : private Empty
{
    int foo;
};

Здесь sizeof(Foo), вероятно, будет 5, но sizeof(Bar) будет 4 из-за пустого базового класса.

0 голосов
/ 22 января 2011

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

class A {
public:
  void foo();
};

class B : private A {
public:
  void bar();
};

void B::bar()
{
  foo();  // can access foo()
}

B b;
b.foo(); // forbidden
b.bar(); // allowed

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

...