一、转换
·规则:
可以使用派生类类型的引用或对象初始化基类类型的引用
可以使用派生类对象(I:引用)对基类对象进行赋值或初始化(#)
存在从派生类引用或指针到基类引用或指针的自动转换
没有从派生类对象到基类对象的直接转换(但存在强制转换,强制转换后被转换的指针指向不变)
·引用转换和转换对象
派生类对象传递到基类引用:基类引用直接绑定到派生类对象(*)
派生类对象传递到基类对象,将派生类对象的基类部分复制到基类对象
用派生类对象对基类对象进行初始化或赋值(#):
初始化-复制构造函数--->首先,将派生类对象传递给基类引用(*),然后用 由基类引用绑定的派生类对象的基类部分 分别对基类对象的成员进行复制或初始化
赋值-赋值操作符--->同上
二、继承情况下的类作用域
·规则:
名字查找在编译时发生,对象、引用或指的静态类型决定了对象能够完成的行为。甚至当静态类型和动态类型可能不同的时候,静态类型仍然决定着可以使用什么成员;
所以基类指针(引用或对象)智能访问对象的基类部分【即使是基类指针指向派生类对象,也只能访问派生类对象的基类部分】
派生类作用域中派生类成员将屏蔽基类的同名成员。即使函数原型不同,基类成员也会被屏蔽。
在派生类对象调用某个函数时,编译器按照名字在派生类中寻找,一旦找到同名,(即使原型不同),编译器就不再继续查找了;只有在派生类中没有定义该函数时,才考虑基类函数。
通过基类调用被屏蔽的虚函数:当类声明或继承了virtual成员函数时,该类会产生一张虚函数表,。。。
名字查找和继承的四个步骤:
(1) 首先确定函数调用的对象、引用或指针的静态类型。
(2) 在该类中查找函数,如果找不到就在直接基类中找,如此循环直到查找到最上层基类。
(3) 一旦找到了改名字就进行常规的参数类型检查。
(4) 假定函数调用是合法的,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定对象的动态类型运行哪个函数版本。
实例:
class A
{};
class B:public A
{};
int main()
{
A *pa=new B();//只是用B的基类部分初始化pa,因此对于pa只能使用基类的成员部分-->原因 : 名字查找在编译时发生
pa->A::fun();//这里,fun()是同时存在与子类和父类的同名函数;如果fun()不是virtual,那么这里就调用A的fun,如果fun()是virtual,即使是A::限定,也是调用B的fun();
}
阅读(605) | 评论(0) | 转发(0) |