前面的博文简要的谈了C++继承的三种方式,以及它们各自的对内,对外的访问权限。那么既然非private的成员函数都可以继承,构造和析构函数呢?另外有没有办法改变继承过来的基类的成员的访问权限,以及如果有同名成员函数的时候怎么处理?
1、C++继承时的构造函数与析构函数。
C++继承的时候可以获得基类全部的成员变量和成员函数,但是只有构造函数和析构函数除外。
(1)构造函数
构造函数的调用顺序是从基类开始构造,一直到最后一个派生类结束。另外,构造函数是可以显式调用的。
构造原则如下:
1. 如果子类没有定义构造方法,则调用父类的无参数的构造方法。
2. 如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法,然后执行自己的构造方法。
3. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数。
4. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数。
5. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。
6. 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式
同样的,析构函数也不会继承,也不能显式的调用,它是由编译器自己调用的,而且顺序是从最深的一个派生类开始析构。另外,析构函数还是可以调用的,不过需要一些特殊的方法。详细见另一篇博文《C++中显示调用构造函数与析构函数》
如果C++类体系中存在继承关系,请注意父子类的析构函数关键字设置。虚函数是在基类中被声明为 virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载。 当一个类作为基类时,它的析构函数应该为虚析构函数(基类析构函数前加virtual关键字),这样才能保证调用子类的析构函数。
如过基类的析构函数不是虚析构函数,根据指针的类型调用析构函数,而不是根据指针指向对象的类型调用析构函数,此时就不能执行子类的析构函数了。
例如下面这个小程序:
如果在A内没有使用虚析构函数的话,那么指向派生类的基类指针就不会去执行派生类的析构函数,从而造成一些不必要的错误。
3、使用using 改变基类成员在派生类的访问权限
class A
{
public:
int f1;
protected:
int f2;
private:
int f3;
};//如下声明只是举例,实际声明中不能重复声明同一成员。
class B : public A //这里的访问标号可以是任意,它只影响没有被显示声明的从基类继承的成员的访问
{
public:
using A::f1; //从基类继承的public成员,此处声明后可以被外部访问
using A::f2; //从基类继承的protected成员,此处声明后可以被外部访问
using A::f3; //声明错误,派生类不可访问基类的private成员,即使声明也不行
protected:
using A::f1; //从基类继承的public成员,此处声明后可以被下级派生类访问,但不能被外部访问
using A::f2; //从基类继承的protected成员,此处声明后可以被下级派生类访问,但不能被外部访问
using A::f3; //声明错误,派生类不可访问基类的private成员,即使声明也不行
private:
using A::f1; //从基类继承的public成员,此处声明后既不能被下级派生类访问,也不能被外部访问
using A::f2; //从基类继承的protected成员,此处声明后既不能被下级派生类访问,也不能被外部访问
using A::f3; //声明错误,派生类不可访问基类的private成员,即使声明也不行
};
4、C++中继承时基类与派生类的“遮蔽”问题
“遮蔽”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
1、如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)
2、如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)