Heim > Fragen und Antworten > Hauptteil
#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.用派生类的指针和基类的指针,当它们都是指向派生类对象的地址的时候,调用同名函数,它们的底层机制是如何实现的?为什么即便指向的是相同的地址,但是它们调用的时候却可以调用不同的函数?编译器层面是如何解释的哦?
PHPz2017-04-17 14:00:28
1, C++11以后static成员可以直接初始化,但是仅限于字面量类型(literal type).
2, 准确的说,是属于基类的成员被初始化,并非匿名,而且这些成员也是派生类的一部分。
3, 这个问题比较大,你可以去了解一下C++的对象内存模型和virtual function的调用机制是怎样的,我可以简单的和你介绍一下:
(1) 带有虚函数里类里有一个隐秘的指针成员(vptr),它指向程序里的一块只读区域里的一张虚表(vtable)。
(2) 带有虚函数的类经过编译后都会有一张对应的虚表。
(3) 这个表里存了实际上这个类里虚函数的实现的函数地址。
(4) 当你调用一个对象的虚函数时,程序就会从它的vptr指向的vtable来找到实际上应当调用的函数。
黄舟2017-04-17 14:00:28
1.只有成员变量和 static 的 const 的变量还有 enum 可以就地初始化,之所以 non-static 的不能够就地初始化,按照 Bjarne Stroustrup 的话来说就是:
A class is typically declared in a header file and a header file is
typically included into many translation units. However, to avoid
complicated linker rules, C++ requires that every object has a unique
definition.
That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
2.作为派生类实例的一部分。
3.这个要分虚函数和非虚函数来考虑,你这里的test()
是非虚函数,所以不会查找 v-table,按照变量的类型定义来查找对应实现;如果是virtual
方法则会按照对象实际的类的对应方法。编译器层面对于你这里的例子而言,单纯的就是相当于std::bind(&B::test, ptr_B)();
和std::bind(&A::test, ptr_A)();
,所以函数实现当然是不同的了。