#include <iostream>
using namespace std;
class A
{
public:
static int a;
int b = 1;
void test()
{
cout << "called A\n";
}
};
int A::a = 10;
class B : public A
{
public:
void test()
{
cout << "called B\n";
}
};
int main()
{
cout << B::a << endl;
B* ptr_B = new B();
ptr_B -> test();
A* ptr_A = (A*)ptr_B;
ptr_A -> test();
cout << ptr_A << ' ' << ptr_B << endl;
return 0;
}
代码如上,自己有几个地方比较困惑。
1.为什么static变量不能就地初始化,c++11不是就已经允许其它变量可以就地初始化吗?
2.当实例化派生类的时候,调用了基类的构造函数,那是相当于有一个匿名的基类对象被构造了吗?还是不存在这样的一个匿名对象,只是基类构造的部分是作为派生类的一部分而存在的?
3.用派生类的指针和基类的指针,当它们都是指向派生类对象的地址的时候,调用同名函数,它们的底层机制是如何实现的?为什么即便指向的是相同的地址,但是它们调用的时候却可以调用不同的函数?编译器层面是如何解释的哦?
1, C++11以後static成員可以直接初始化,但是僅限於字面量類型(literal type).
2, 準確的說,是屬於基類的成員被初始化,並非匿名,而且這些成員也是衍生類別的一部分。
3, 這個問題比較大,你可以去了解一下C++的物件記憶體模型和virtual function的呼叫機制是怎樣的,我可以簡單的跟你介紹一下:
(1) 有虛函數裡類別裡有一個隱密的指標成員(vptr),它指向程式裡的一塊唯讀區域裡的一張虛表(vtable)。
(2) 帶有虛函數的類別經過編譯後都會有一張對應的虛表。
(3) 這個表裡存了實際上這個類別裡虛函數的實作的函數位址。
(4) 當你呼叫一個物件的虛擬函數時,程式就會從它的vptr指向的vtable來找出實際上應當呼叫的函數。
1.只有成員變數和 static 的 const 的變數還有 enum 可以就地初始化,之所以 non-static 的不能夠就地初始化,按照 Bjarne Stroustrup 的話來說就是:
2.作為衍生類別實例的一部分。3.這個要分虛函數和非虛函數來考慮,你這裡的
是非虛函數,所以不會查找v-table,按照變量的類型定義來查找對應實現;如果是
test()
方法則會依照物件實際的類別的對應方法。編譯器層面對於你這裡的例子而言,單純的就是相當於virtual
和std::bind(&B::test, ptr_B)();
,所以函數實作當然是不同的了。std::bind(&A::test, ptr_A)();