C++中的继承分为三种继承方式:
public,protected,private。
继承会导致父类中的成员访问属性发生变化。
继承机制中,子类访问父类成员方式
不管什么继承,父类的private成员始终为父类私有。
public继承:父类的public和protected成员在子类中访问属性不变
private继承:父类的public和protected成员在子类中变成private
protected继承:父类public和protected成员在子类中变成protected
例子1:
class Base{
public:
Base()
{
printf("Base构造函数\n");
}
~Base()
{
printf("Base析构函数\n");
}
};
class Derive : public Base{
public:
Derive()
{
printf("Derive构造函数\n");
}
~Derive()
{
printf("Derive析构函数\n");
}
};
int main()
{
Base* d = new Derive();
delete d;
return 0;
}
这段代码输出:
Base构造函数
Derive构造函数
Base析构函数
分析:
主函数中Base* d = new Derive(),new一个Base类型的指针实例。
因为子类是继承父类的,所以调用子类的构造方法之前,必然会首先调用父类的构造方法(初始化父类的一些成员变量);
new出来的实例是Base类型的,所以delete时,会调用Base的析构函数。
例子2:
将例1中的主函数变为:
Derive* d = new Derive();
delete d;
输出:
Base构造函数
Derive构造函数
Derive析构函数
Base析构函数
分析:
构造函数的调用顺序与例1一样,不同的是这次new出来的实例指向了Derive类型的指针,因为Derive继承了Base类中成员变量和函数,所以生成Derive类型实例的同时,必然会产生Base类型的实例。
根据析构函数的调用顺序,先构造后析构,因此输出结果如上。
例子3:
将例1中Base的析构函数改为virtual函数:
virtual ~Base()
{
printf("Base析构函数\n");
}
输出结果:
Base构造函数
Derive构造函数
Derive析构函数
Base析构函数
可以看出,输出结果与例2一样。
构造函数的调用顺序与上面的例子一样,这次因为Base的析构函数成了虚函数,父类指针指向子类的实例,所以在调用父类的析构函数时,会有多态效果,实际调用的是子类的析构函数。
delete d的时候,先析构继承类,再析构父类。
实际上,我们在使用类的析构函数时,一般都把析构函数设为虚函数。
在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。
例子4:
class Base{
public:
Base(int num)
{
num_ = num;
printf("Base构造函数,num=%d\n", num_);
}
~Base()
{
printf("Base析构函数\n");
}
virtual void Show()
{
printf("Show:%d\n",num_);
}
protected:
int num_;
};
class Derive : public Base{
public:
Derive(int num, int age):Base(num)
{
age_ = age;
printf("Derive构造函数,age=%d\n", age_);
}
~Derive()
{
printf("Derive析构函数\n");
}
void Show()
{
printf("Show, num:%d, age:%d\n", num_, age_);
}
private:
int age_;
int num_;
};
int main()
{
Base* d = new Derive(1,3);
d->Show();
delete d;
return 0;
}
输出:
Base构造函数,num=1
Derive构造函数,age=3
Show, num:-842150451, age:3
Base析构函数
子类的成员变量和函数名是可以跟父类相同的。
继承类的构造函数需要“继承”基类的构造函数,因为在构造子类时,必然要构造基类。
用:符号来“继承”。
如:Derive(int num, int age):Base(num)
当继承类的成员变量名与基类相同时,以继承类为准。
当基类的成员函数修饰为virtual函数时,指向基类的继承类实例调用函数时,调用的是继承类的方法。