C++——派生类中的访问——可见性问题
C++中派生类对基类成员的访问形式主要有以下两种:
1、内部访问:由派生类中新增成员对基类继承来的成员的访问。
2、对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问。今天给大家介绍在3中继承方式下,派生类对基类成员的访问规则。
1、私有继承的访问规则
当类的继承方式为私有继承时,基类的public成员和protected成员被继承后成为派生类的private成员,派生类的其它成员可以直接访问它们,但是在类的外部通过派生类的对象无法访问。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类的成员还是通过派生类的对象,都无法直接访问从基类继承来的private成员,但是可以通过基类提供的public成员函数间接访问。私有继承的访问规则总结如下:
基类成员 private成员 public成员 protected成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 不可访问 不可访问
2、公有继承的访问规则
当类的继承方式为公有继承时,基类的public成员和protected成员被继承到派生类中仍作为派生类的public成员和protected成员,派生类的其它成员可以直接访问它们。但是,类的外部使用者只能通过派生类的对象访问继承来的public成员。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是派生类的对象,都无法直接访问从基类继承来的private成员,但是可以通过基类提供的public成员函数直接访问它们。公有继承的访问规则总结如下:
基类成员 private成员 public成员 protected成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 可访问 不可访问
3、保护继承的访问规则
当类的继承方式为保护继承时,基类的public成员和protected成员被继承到派生类中都作为派生类的protected成员,派生类的其它成员可以直接访问它们,但是类的外部使用者不能通过派生类的对象访问它们。基类的private成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是通过派生类的对象,都无法直接访问基类中的private成员。保护继承的访问规则总结如下:
基类成员 private成员 public成员 protected成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 不可访问 不可访问
派生类中的访问——可见性问题
1、 对于在不同作用域声明的标识符,可见性原则:
若存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,则外层标识符在内层仍然可见;
若在内层声明了同名标识符,则外层标识符在内层不可见,这时内层变量隐藏了外层的同名变量,这种现象称为隐藏规则。
其中,外层为基类,内层为派生类。
2、 作用域:
使用::作用域限定要访问的成员所在类的名称。
基类和派生类新增的成员都具有类作用域,但作用范围不同:是相互保护的两个层,派生类在内层。
(1)单继承中的同名隐藏
在没有使用虚函数的情况下,若派生类声明了一个和基类成员同名的新成员函数,即使函数的参数表不同,那么从基类继承的同名函数的所有重载形式也都被隐藏(外层基类中的同名成员函数被隐藏),使用成员名只能访问到派生类的成员函数。若要访问被隐藏的基类成员,必须使用基类名和作用域符::限定,使用基类名::成员名访问。
隐藏规则在私有继承中的应用
在私有继承时,为保证基类的公有成员能在派生类中访问,必须在派生类中重新声明同名的成员。在调用时,根据同名隐藏的规则,使用派生类中的函数。若对基类继承过来的某些函数功能进行扩充和改造,可以通过隐藏实现。
(2)多继承中的同名隐藏及访问冲突问题
①各基类没有任何继承关系,同时没有共同基类的情况:
在没有使用虚函数的情况下,若派生类的多个基类拥有同名的成员,同时派生类又新增了同名的成员函数时,派生类将隐藏所有基类的同名函数。
隐藏访问及隐藏冲突:
A 使用“对象名.成员名”可唯一标识和访问新增派生类成员;——隐藏
B 只有使用“对象名.基类名::成员名”这种作用域标识符可以访问基类的同名成员;
C若派生类没有声明同名函数,使用“对象名.成员名”无法唯一标示成员——冲突!
只能通过“对象名.基类名::成员名”访问基类的成员。
② 有间接基类的情况
A
B1 B2
C
对于派生类C,其直接基类B1、B2,间接基类A。
若B1 B2分别定义了同名的成员,而派生类C没有新增该同名函数,则使用“类C的对象名.成员名”产生冲突!只能使用“类C的对象名.B1/B2::成员名”可以访问B1/B2中的同名成员;但任何方式都无法访问A中的同名成员。(同①)
若要访问类A中的成员,而在B1 B 2 C中没有新增同名的成员,通过“类C的对象名.A中成员名”或“类C的对象名.A::A中成员名”访问类A中的成员,产生冲突!只有通过
“类C的对象名.B1/B2::成员名”访问类A中的成员。
若派生类C声明了同名函数,则使用“类C的对象名.成员名”访问的是C类新增的同名成员函数——隐藏
小结:
同名成员的唯一标识问题:
•使用作用域符::唯一标识派生类中由直接基类继承的成员;
派生类对象.直接基类名::同名成员/同名成员函数
•将共同基类设置为虚基类,这时从不同的路径继承过来的同名成员在内存中只要一个拷贝,同一个函数也只有一个路径。声明虚基类是在派生类定义过程中进行的:
class 派生类名:virtual 继承方式 基类名