2017-02-16 3 views
1
#include<iostream> 
using namespace std; 

class A 
{ 
    int a; 
public: 
    int a_p; 
    void displayA() 
    { 
    cout<<"A::a "<<a<<endl; 
    } 
    void displayAP() 
    { 
    cout<<"A::a_p "<<a_p<<endl; 
    } 
    void get_a(int x) 
    { 
    a=x; 
    } 
}; 

class B:public A 
{ 
    int b; 
public: 
    void displayB() 
    { 
    cout<<"A::a_p "<<a_p<<endl; 
    } 
}; 

int main() 
{ 
    B b1,b2; 
    b1.get_a(5); 
    b2.get_a(10); 

    b1.displayA(); 
    b2.displayA(); 

    cout<<"......"<<endl; 

    b1.a_p=25; 
    b1.displayB(); 
    b1.displayAP(); 
} 

Я требуют уточнения для следующего:Как наследование действительно работает?

  • Первые 5 заявления по главной дать выход в 5,10. Хотя a, который является частной переменной-членом class A, не наследуется, кажется, что у каждого объекта class B есть копия a. Можете ли вы сообщить мне, что здесь происходит?

  • 6-утверждение в основных наборах a_p из class B до 25. displayB() функции показывает значение a_p из class B и функции displayAP() показывает значение a_p из class A. Тем не менее, выход составляет 25 для обоих. Можете ли вы объяснить эту часть?

    функция

ответ

0

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

Вторая пуля указывает, что вы ошибаетесь. Они оба указывают на A :: a_p (свойство, содержащееся в классе A). Поскольку B не содержит свойства A_P него не будет неявно указать на один в A.

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

#include<iostream> 

class A { 

public: 
    int a; 
}; 

class B : public A { 
public: 
    int a; 

    B() = delete; 
    B(int a_a, int b_a) { 
     A::a = a_a; 
     a = b_a; 
    } 

    void displayA_A() { 
     std::cout << "A::a: " << A::a << std::endl; 
    } 

    void displayB_A() { 
     std::cout << "B::a " << B::a << std::endl; 
    } 
}; 

int main() { 
    B b(10,20); 

    b.displayA_A(); 
    b.displayB_A(); 

    return 0; 
} 

Когда вы строите B в основном , сначала будет создан объект A, а его член будет установлен в 10. Тогда член внутри B будет установлен в 20.

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

0

displayAP() показывает значение A_P класса А.

Как вы можете быть уверены в том, что ?, b1.displayAP(); разве вызова A::displayA() но B::displayA() потому что b1 имеет тип B. (B унаследовал все ваши A свойства.). Даже этот номер b1.a_p=25; присваивает B::a_p со значением 25.

Можете ли вы сообщить мне, что здесь происходит?

Это не копия, наследование в C++ (хорошо во всех языке тоже) наследует все члены своего родителя независимо от того, что спецификатор элемент находится под, а также их Спецификатор доступа остается тем же самым.

Итак, что выход это дает вам правильно специально на ваших «первые 5 заявлений под основной»

Вы должны прочитать больше о наследовании http://www.learncpp.com/cpp-tutorial/112-basic-inheritance-in-c/

1

Короткий ответ: Наследование похоже на куклу Матрёшки, и каждый класс полностью содержит все базовые классы (если они есть).

Длинный ответ: Когда класс наследуется от одного или нескольких других классов, производный класс содержит его родительский класс (ы), который, в свою очередь, содержит их родительский класс (ы), пока вы не достигнете наименее производного класса (es) (класс (es), который не имеет собственных родительских классов). Так, например, с этой установкой:

class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {}; 
class E : public D {}; 

E содержит D, который содержит B (который содержит A) и C (который содержит другой A); это выглядит примерно так (сгенерировано с помощью MSVC, используя compiler option /d1reportSingleClassLayoutE в an online x64 environment).

class E size(1): 
     +--- 
     | +--- (base class D) 
     | | +--- (base class B) 
     | | | +--- (base class A) 
     | | | +--- 
     | | +--- 
     | | +--- (base class C) 
     | | | +--- (base class A) 
     | | | +--- 
     | | +--- 
     | +--- 
     +--- 

Обратите внимание, что эта аналогия немного не для virtual базовых классов, которые имеют тенденцию быть расположены сразу после наиболее производного класса „основное тело“ (из-за отсутствия лучшего термина, память, выделенная для всех не - virtual базовых классов и элементов данных) в памяти.

class A {}; 
class B : public virtual A {}; 
class C : public virtual A {}; 
class D : public B, public C {}; 
class E : public D {}; 

E содержит D, который содержит B и C. E имеет один экземпляр A, выведенный на спину.

class E size(16): 
     +--- 
     | +--- (base class D) 
     | | +--- (base class B) 
0  | | | {vbptr} 
     | | +--- 
     | | +--- (base class C) 
8  | | | {vbptr} 
     | | +--- 
     | +--- 
     +--- 
     +--- (virtual base A) 
     +--- 

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

class A { private: int a; protected: int b; public: int c; }; 
class B { public: int d; }; 
class C : public A, public B { protected: int e; }; 
class D : public C {}; 

static_assert(sizeof(C) == sizeof(A) + sizeof(B) + sizeof(int), "Size mismatch."); 
static_assert(sizeof(D) == sizeof(C),       "Size mismatch."); 
static_assert(sizeof(D) == sizeof(int) * 5,      "Size mismatch."); 

D содержит C, которая содержит A (который содержит 3 int с), B (который содержит int), и int. Ни Clang, GCC, ни MSVC не выдадут ошибку Size mismatch.. Использование /d1reportSingleClassLayoutD ...

class D size(20): 
     +--- 
     | +--- (base class C) 
     | | +--- (base class A) 
0  | | | a 
4  | | | b 
8  | | | c 
     | | +--- 
     | | +--- (base class B) 
12  | | | d 
     | | +--- 
16  | | e 
     | +--- 
     +--- 

Таким образом, спецификаторы доступа фактически не влияет на то, что это или не передается по наследству. Что они do влияют, однако, на то, что видно на производный класс.

  • private участников видны только в классе, где они заявлены. a видна в A, но не в C или D
  • protected Участники видны по всей иерархии наследования после того, как они столкнулись. b видна в A, C и D (но не в B, так как она не наследуется от A). e видна в C и D.
  • public Участников обнажают, чтобы увидеть мир. c и d видны повсюду.

Все члены, объявленные в классе, могут видеть любой член, который видим их класс. Используя ваш пример, A::displayA() всегда может видеть A::a, даже если вызывается экземпляр производного класса B; Однако, если B заявляет член displayA(), скрывающую A::displayA(), то B::displayA() не будет в состоянии видеть A::a, и придется полагаться на public или protected членов A, если он хочет работать с A::a.

class A { 
    int a; 

    public: 
    void displayA() { std::cout << "A::a " << a << std::endl; } 
}; 

class B : public A { 
    public: 
    // Will emit some variation on "A::a is private, you can't access it here." 
    // Note that no compiler will claim that it doesn't exist. 
    // void displayA() { std::cout << "A::a " << a << std::endl; } 

    // This works, though, since it goes through A::displayA(), which can see A::a. 
    void displayA() { return A::displayA(); } 
}; 
Смежные вопросы