環境:2010
代碼:
#include <iostream>
using namespace std;
class A
{
public:
A() {
a = 0;
cout<<"A::A()"<<endl;
}
int a;
};
class B:protected A
{
public:
B() {
i=1;
cout<<"B::B()"<<endl;
}
public:
int i;
};
int main(void){
B b2;
b2.i = 20;
A *pp = (A*)&b2;
cout<<"pp->a: "<<pp->a<<" "<<"b2.i "<<b2.i<<endl;
return 0;
}
void SetB(int n){
this->a = n;
}
class B{
public:
virtual void Show(){cout<<'B'<<endl;}
};
class D:public B{
public:
void Show(){cout<<'D'<<endl;}
};
void fun1(B* ptr){ptr->Show();}
void fun2(B& ref){ref.Show();}
void fun3(B b){b.Show();}
int main(void){
B b,*p=new D;
D d;
fun1(p);
fun2(b);
fun3(d);
return 0;
}
讀者可以思考一下輸出結果。
現在來看輸出結果:
分析:主函數裡基類類型的指針指向派生類,fun1()裡傳的是指向派生類的指針,又因為函數show是虛函數,所以這裡應該調用的是派生類的show方法。fun2()傳的是基類的對象,fun2()裡是對對象的引用,所以這裡應該調用的是基類的show方法。fun3()裡傳的是對象,即使傳的是對象D,但因為fun()裡是B對象,初始化時使用的是B類的復制構造函數。由於復制構造函數接收的是B類型的常引用,d又符合類型兼容規則,所以可以作為參數傳給它。由於執行的是B的復制構造函數,只要B類型的成員會被復制,d類的不會復制,也沒有空間存儲,所以生成的是對象是基類的B對象,進而輸出的是'B'。
總結:基類的指針可以指向派生類的對象,基類的引用可以作為派生類的別名,但基類的對象不能表示派生類的對象
摘自 Wentasy