Почему размер производного класса включает закрытые члены базового класса? - PullRequest
4 голосов
/ 04 июля 2011

У меня есть следующий код:

class A {
  private:
    int i;
 };

class B : public A {
 private:
  int j;
 };

Когда я проверяю sizeof(B), это выглядит как sizeof(base) + sizeof(derived). Однако я понимаю, что наследование состоит в том, что private члены базового класса не наследуются. Почему тогда они включены в результат sizeof(B)?

Ответы [ 7 ]

8 голосов
/ 04 июля 2011

все переменные-члены наследуются.модификаторы private protected public изменяют только те, кто имеет доступ к этим переменным

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

Вы неправильно понимаете, что делает private.В вашем фрагменте кода он просто предотвращает доступ не * участников и не друзей A к i.Это просто модификатор access-control .Экземпляры B будут иметь элементы данных A, хотя B не будет иметь (прямого) доступа к нему.

Аналогия, показывающая, что это действительно имеет смысл:

class Human
{
protected:
    void UseCognitivePowers() { brain.Process(); }
private:
    Brain brain;
    // ...
};

class StackOverflowUserInSilico : public Human
{
private:
    void AnswerStackOverflowQuestion(int questionId)
    {
        // ...
        // magic occurs here
        // ...
        UseCognitivePowers();
    }
};

Несмотря на то, что brain является приватным в классе Human, StackOverflowUserInSilico будет иметь Brain, поскольку StackOverflowUserInSilico происходит от Human.Это необходимо, иначе функция UseCognitivePowers() не будет работать, даже если StackOverflowUserInSilico наследует метод от Human.

Конечно, будут ли подклассы Human на самом деле использовать UseCognitivePowers()метод, предоставленный им классом Human, является совершенно другим вопросом.

4 голосов
/ 04 июля 2011

Вы либо неправильно поняли sizeof, либо неправильно поняли расположение (в памяти) объектов C ++.

По соображениям производительности (чтобы избежать затрат на косвенное обращение) компиляторы часто реализуют деривацию с использованием Composition:

// A
+---+
| i |
+---+

// B
+---+---+
| A | j |
+---+---+

Обратите внимание, что если private, B не может заглянуть в A, даже если оно его содержит.

Оператор sizeof вернет размер B,включая необходимые отступы (для коррекции выравнивания), если таковые имеются.

Если вы хотите узнать больше, я от всей души рекомендую Внутри объектной модели C ++ от Стэнли А. Липпман ,Несмотря на то, что компилятор зависит, многие компиляторы фактически используют одни и те же базовые принципы.

3 голосов
/ 04 июля 2011

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

2 голосов
/ 04 июля 2011

На это уже был дан ответ в нескольких других ответах: спецификаторы доступа ограничивают доступ , но атрибуты-члены класса все еще наследуются.

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

class base {
   int x;
public:
   base() : x(0) {}
// ...
   void printout() {
      std::cout << x << std::endl;
   }
};
class derived : public base {
// ... assume that derived does not hide `printout`
};
int main() {
   derived d;
   d.printout();  // this requires access to d.base::x
}

Это всего лишь простойпример, и есть несколько вещей, которые вы можете здесь сказать, чтобы доказать, что в некоторых случаях x можно сделать ненужным (мы переопределяем / скрываем printout в производном объекте ...), ноязык по-прежнему позволяет вам получить доступ к скрытому / переопределенному методу-члену путем квалификации, поэтому d.base::printout() все равно будет обращаться к printout на базовом уровне, а для этого по очереди требуется x.

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

Я не знаю, что это за язык, но когда вы наследуете, оригинальный объект все еще существует. вот почему вы все еще можете вызвать base.method ()

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

Спецификаторы доступа (открытый / закрытый / защищенный) никоим образом не влияют на унаследованный «размер объекта».

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