关于C++ 的继承 多态 和与之相关的对象模型知识,各个书本上很多了
今天来看几个对象模型的问题 在实践中理解C++ 对象模型:
1、 在下列代码中:
class A
{
public :
A()
:_a(1)
{}
virtual void FunTestA()
{}
int _a;
};
class B
{
public:
B()
:_b(2)
{}
virtual void FuntestB()
{}
int _b;
};
class C :public A, public B
{
public :
C()
:A()
, B()
, _c(3)
{}
int _c;
};
void Fun()
{
C c;
cout << sizeof(c) << endl;
A* pA = &c;
B* pB = &c;
C* pC = &c;
}
`
nt main()
{
Fun();
return 0;
}
选项:
A pA、pB、pC的取值相同
B、 pC 和 pA不相同
C、pB和pC不相同
D、pC不等于pA,也不等于pB。
解析:在继承体系中,当用一个基类的指针或引用指向派生类对象时(赋值兼容规则),这时会将派生类对象的地址偏移一个合适偏移量,因为派生类对象也是一个基类对象,实际也就是让基类指针指向派生类中属于基类的那部分。所以一般先继承的那个类(基类)的指针和派生类的对象的地址相等。
2、 类A 与类 B毫无关系
class A
{
public :
A()
{
m_a = 1;
m_b = 2;
}
void fun()
{
cout << m_a <<" "<< m_b << endl;
}
private :
int m_a;
int m_b;
};
class B
{
public :
B()
{
m_c = 3;
}
void fun()
{
cout << m_c << endl;
}
private :
int m_c;
};
void Fun()
{
A a;
B* pb = (B*)(&a);
pb->fun();
}
int main()
{
Fun();
return 0;
}
A 类与 B 类毫无关系,则pd->fun();一定到用的是派生类的fun()函数,
但是pb又是被强制指向A类对象的,
那么肯定会打印前A类对象前四个字节的值,也就是1。(因为B类大小就是4个字节)。因为B类的大小的4个字节,所以B类的指针管理的内存范围是4个字节。
3、 当B类共有继承A类的时候
class A
{
public :
A()
{
m_a = 1;
m_b = 2;
}
void fun()
{
cout << m_a <<" "<< m_b << endl;
}
private :
int m_a;
int m_b;
};
class B:public A
{
public :
B()
:A()
{
m_c = 3;
}
void fun()
{
cout << m_c << endl;
}
private :
int m_c;
};
void Fun()
{
A a;
B* pb = (B*)(&a);//切记:这里是派生类的指针指向基类对象
//没有定义基类。
pb->fun();
}
int main()
{
Fun();
return 0;
}
这里pd->fun()还是调用的派生类的fun函数,可这时派生类继承了基类,所以派生类的指针管理的范围就是 (4 + 8) = 12个字节。而继承基类A的派生类B 并没有被定义,m_c的空间还没有开辟出来,所以这时候打印m_c结过时崩溃或随机数。
4、当A类的fun函数被声明为虚函数时,并且定义了B类时。
class A
{
public :
A()
{
m_a = 1;
m_b = 2;
}
virtual void fun()//虚函数
{
cout << m_a <<" "<< m_b << endl;
}
private :
int m_a;
int m_b;
};
class B:public A
{
public :
B()
:A()
{
m_c = 3;
}
void fun()//重写
{
cout << m_c << endl;
}
private :
int m_c;
};
void Fun()
{
A a;
B b;//注意这里定义了B类
B* pb = (B*)(&a);//切记:这里是派生类的指针指向基类对象,不会形成多态
pb->fun();//在A类的虚表内找fun函数(调用的是A类的fun函数),输出1和2
A* pa = (A*) &b;
pa->fun();//这里形成了多态 打印 。
}
这里虽然定义了B类,但是没有形成多态,pb实际上指向的是A的空间pd->fun()是在A的虚表中找vptr 函数指针 所以调用的是A的fun()函数。
4、 如果是基类fun函数是普通函数,派生类fun()函数是虚函数
class A
{
public:
A()
{
m_a = 1;
m_b = 2;
}
void fun()
{
cout << m_a << " " << m_b << endl;
}
private:
int m_a;
int m_b;
};
class B :public A
{
public:
B()
:A()
{
m_c = 3;
}
virtual void fun()
{
cout << m_c << endl;
}
private:
int m_c;
};
void Fun()
{
A a;
B b;
B* pb = (B*)(&a);//切记:这里是派生类的指针指向基类对象
pb->fun();
A* pa = (A*) &b;
pa->fun();
}
int main()
{
Fun();
system("pause");
return 0;
}
这时候仍然没有形成多态, 但是B类的fun()函数是虚函数,pb指向&a.所以pb->fun()这一句,会在 A对象的前四个字节中寻找虚表,所以他把m_a当成虚表使得程序崩溃。
这里是因为没有形成多态,所以pb虽然指向&a但是pb的类型是B* pb会按照B类的结构来解释在A类内存空间中的数据。