注意:本文中代码均使用 Qt 开发编译环境
作用域分辨符,就是经常见到的“::”,他可以用来限定要访问的成员所在的类的名称,一般形式是:
基类名::成员名; // 数据成员
基类名::成员名(参数表); // 函数成员
在没有虚函数的情况下,如果派生类中声明了与基类成员函数同名的新函数,即使函数的参数表不相同,从基类继承的同名函数的所有重载形式也都会被隐藏。如果想要访问被隐藏的成员,就需要使用作用域分辨符和基类名来限定。
在没有虚函数的情况下,如果某个派生类的多个基类拥有同名的成员,同时,派生类又新增这样的同名成员,在这种情况下,派生类成员将隐藏所有基类同名成员。这时使用“对象名.成员名”方式可以唯一标识和访问派生类新增成员,基类同名成员也可以。
但是如果派生类在多继承的时候,没有声明这样新的同名成员。这时就必须通过使用基类名和作用域分辨符来标识成员。
示例:
#include <QCoreApplication>
#include <QDebug>
class B1 {
public:
int nV;
void fun(){qDebug()<<"Memberof B1"<<", nV = "<<nV;}
};
class B2 {
public:
int nV;
void fun(){qDebug()<<"Memberof B2"<<", nV = "<<nV;}
};
class C : public B1, public B2 {
public:
int nV;
void fun(){qDebug()<<"Memberof C"<<", nV = "<<nV;}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
C c1;
c1.nV = 1;
c1.fun();
c1.B1::nV = 2;
c1.B1::fun();
c1.fun();
c1.B2::nV = 3;
c1.B2::fun();
c1.fun();
return a.exec();
}
示例运行结果:
运行结果
通过作用域分辨符,就明确地唯一标识了派生类中由基类所继承来的成员,达到访问的目的,解决了成员被隐藏的问题。
如果派生类没有声明新的与基类同名的成员。
例如,将上例中的派生类C,改为如下形式:
class C : public B1, public B2 {
};
再次,运行会出现报错:
错误信息
我们注释掉会导致出错的代码,再次运行,输出结果:
注释错误代码后的输出
如果某个派生类的部分或者全部直接基类是从另一个共同的基类派生而来,在这些直接基类中,从上一级基类继承来的成员就拥有相同的名称,因此派生类中也就会产生同名现象,对这种类型的同名成员也要使用作用域分辨符来唯一标识,而且必须用直接基类来进行界定。
#include <QCoreApplication>
#include <QDebug>
class B0 {
public:
int nV = 0;
void fun(){qDebug()<<"Memberof B0 and nV = "<<nV;}
};
class B1:public B0 {
public:
int nV1;
};
class B2:public B0 {
public:
int nV2;
};
class C:public B1, public B2 {
public:
int nVd;
void fun(){qDebug()<<"Memberof C";}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
C c1;
c1.B1::nV = 2;
c1.B1::fun();
c1.B2::nV = 3;
c1.B2::fun();
c1.B1::fun();
return a.exec();
}
运行结果:
运行结果
在例子中可以看出,在这种情况下,派生类的对象在内存中就同时拥有成员nV及fun的两份同名拷贝。