在讲派生类的构造和析构函数时候我们先介绍类的兼容性。
类的兼容性:
类的兼容性是指在需要基类对象的任何地方都可以使用派生类来替代,通过继承,派生类得到了除了基类构造函数,复制函数中的所有成员。这样公有派生类实际具备了基类所有的功能,凡是基类所能解决的问题,公有派生类都可以解决。类的兼容性规则中所指代的情况有以下几种
1)派生类的对象可以隐含转化为基类对象
2)派生类对象可以初始化基类的应用
3)派生类的指针可以初始化基类的指针
在替代之后,派生类对象可以作为基类对象使用,但只能使用从基类继承的成员。
派生类的构造和析构函数
继承的目的是为了发展,派生类继承了基类的成员,实现原有代码的重用,这只是一部分,类的派生只有通过添加新的成员,加入新的功能,类的派生才有实际意义。
构造函数
定义了派生类以后,要使用派生类就需要声明该类的对象,对象在使用之前必须进行初始化。派生类的对象是由所有的基类成员对象与派生类新增成员对象共同组成。
因此在构造派生类对象时,就需要对基类的成员对象和新增成员对象初始化。基类的构造函数并没有继承下来,要完成这些工作就必须给派生类添加新的构造函数。派生类对于很多基类成员对象是不能够直接访问的,因此要玩车个对基类对象的初始化工作,需要调用基类的构造函数。构造函数的形式
派生类名::派生类名(参数表):基类名1(基类1初始化参数表),.....,基类名n(基类n初始化参数表),成员对象名1(成员对象1初始化参数表)
{
派生类构造函数的其他初始化操作;
}
下面说明什么时候要声明派生类的构造函数。如果对基类初始化时,需要调用基类的带有形参表的构造函数时,派生类就必须声明构造函数。
派生类构造函数执行次序一般如下:
1)调用基类构造函数,调用顺序按照他们被继承时声明的顺序。
2)对派生类新增成员进行对象的初始化,调用的顺序按照他们被继承时声明的顺序(从左向右)。
3)执行派生类的构造函数体中的内容。
下面进行举例
#include<iostream>
#include<string>
#include"rectangle.h"
using namespace std;
//基类base1
class base1
{
public:
base1(int j){ cout << "base1" << endl; }
};
//基类base2
class base2
{
public:
base2(int i) { cout << "base2" <<" " <<i<< endl; }
};
//基类base3
class base3
{
public:
base3() { cout << "base3" << endl; }
};
//派生类
class rui:public base1 ,public base2,public base3
{ public:
rui(int a, int b, int c):test1(a), test2(b),base1(a), base2(b){
cout << "rui called" << endl;
}
private:
base1 test1;
base3 test3;
base2 test2;
};
int main()
{
rui test1(0,2,3);
}
运行结果如下:
以上我们可以看到函数的构造顺序。下面介绍复制构造函数。
如果程序员没有编写复制构造函数时,那么编译系统会在必要时编写一个默认复制构造函数,如果需要为派生类编写复制构造函数,一般需要给基类的复制构造函数传递参数。复制构造函数的基本语句为
派生类(派生类名 &v1):基类(v1)
{...}
我们知道,对于基类的复制构造函数来说,我们应该使用基类的引用,但是我们在上文类的兼容性提出到可以使用派生类代替基类的引用,因此参数也可以为派生类。上面的构造函数注意深复制与浅复制的问题,如果想要完全进行地址的复制需要进行动态内存分配,下面我简单编写一个例子使得大家能够轻松理解使用方式,定义了一个基类,和一个派生类,并定义了一些外部的接口,代码如下:
#include<iostream>
#include<string>
using namespace std;
//基类
class girl
{
private:
//个人信息
string name;
int height;
int age;
int weight;
public:
//外部接口
int getheight() { return height; }
int getage() { return age; }
int getweight() { return weight; }
string getname() { return name; }
//改变年龄
void change(int agea) {
age = agea;
}
//构造函数
girl(string name1="zhang", int height1=178, int age=23, int weight=60):name(name1), height(height1), age(age), weight(weight)
{
cout << "girl is called" << endl;
}
};
//派生类
class rui:public girl {
private:
//组合类可以但是继承类不可以,因为会被初始化两次
//girl * girls;
int *girls;
public:
//构造函数
rui(string name, int height, int age, int weight,int & girls1): girl(name, height, age, weight)
{
girls = girls;
}
//复制构造函数
rui(rui & v1) :girl(v1) {
//动态内存分配,可以进行深复制
girls = new int ;
girls = v1.girls;
cout << "called copy " << endl;
}
~rui()
{ //析构函数释放内存
cout << "delete" << endl;
delete girls;
}
//接口,其实也可以在类外通过对象名.成员名来显示
void girl1height() { cout << "女孩的身高"<<getheight(); }
};
int main()
{
girl girl1;
int girls =1;
//初始化寒素
rui test( "zhang",4165, 23, 60, girls);
cout << test.getage() << endl;
rui test1(test);
cout << test1.getage() << endl;
//测试复制构造函数
test.change(3);
cout << test.getage() << endl;
cout << test1.getage() << endl;
}
析构函数
析构函数一般用来释放内存。对于动态内存,记得释放。