类-派生和继承
1.基本概念
- 继承:保持已有类的特性而构造新类的过程
- 派生:在已有类的基础上新增自己的特性而产生新类的过程
2. 语法
单继承(一个父类)
/*
class 派生类名: 继承方式 基类名
{
成员声明;
}
*/
// eg:
class Derived: public Base
{
public:
Derived ();
~Derived ();
};
多继承(有多个父类)
/*
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...
{
成员声明;
}
*/
//eg:
class Derived: public Base1, private Base2
{
public:
Derived ();
~Derived ();
};
派生类的构成:
- 默认情况下继承除构造函数和析构函数以外的所有成员
- 派生类声明了一个和某基类成员同名的新成员,派生的新成员就隐藏或覆盖了外层同名成员
- 派生类增加新成员使派生类在功能上有所发展
3. 继承方式
不同继承方式的差别体现在:
- 派生类对基类成员的访问权限
- 通过派生类的对象对基类成员的访问权限
权限的优先级:public < protected < private。继承之后父类的成员在子类中的权限不低于继承方式的权限,即:
public不改变权限
protected:public——>protected
private:public, protected——>private
父类的private一直不能被子类访问
4. 类型转换
- 公有派生类对象可以被当作基类的对象使用,反之则不可。
- 派生类的对象可以隐含转换为基类对象;
- 派生类的对象可以初始化基类的引用;
- 派生类的指针可以隐含转换为基类的指针。
- 通过基类对象名、指针只能使用从基类继承的成员。
#include <iostream>
using namespace std; class Base1 { //基类Base1定义
public:
void display() const {
cout << "Base1::display()" << endl;
}
};
class Base2 : public Base1 { //公有派生类Base2定义
public:
void display() const {
cout << "Base2::display()" << endl;
}
};
class Derived : public Base2 { //公有派生类Derived定义
public:
void display() const {
cout << "Derived::display()" << endl;
}
};
void fun(Base1* ptr) { //参数为指向基类对象的指针
ptr->display(); //"对象指针->成员名"
}
int main() { //主函数
Base1 base1; //声明Base1类对象
Base2 base2; //声明Base2类对象
Derived derived; //声明Derived类对象
fun(&base1); //用Base1对象的指针调用fun函数
fun(&base2); //用Base2对象的指针调用fun函数
fun(&derived); //用Derived对象的指针调用fun函数
return 0;
}
都只能调用基类的display函数,即不要重写继承的非虚函数
5. 派生类的构造、析构函数
构造函数
-
默认情况下不继承基类的构造函数,使用
using Base::Base()
指定继承基类构造函数,此时只能用构造函数对基类成员初始化 -
自行定义构造函数:
- 派生类新增成员:派生类定义构造函数初始化;
- 继承来的成员:自动调用基类构造函数进行初始化;
- 派生类的构造函数需要给基类的构造函数传递参数。
-
语法:多继承+组合类
-
派生类名::派生类名(形参表): 基类名1(参数), 基类名2(参数), ..., 基类名n(参数), 本类成员(含对象成员)初始化列表 { //其他初始化 };
-
构造函数的执行顺序
-
调用基类构造函数。
顺序按照它们被继承时声明的顺序(从左向右)。
-
对初始化列表中的成员进行初始化。
顺序按照它们在类中定义的顺序。
对象成员初化时自动调用其所属类的构造函数。由初始化列表提供参数。
-
执行派生类的构造函数体中的内容。
复制构造函数
- 一般都要为基类的复制构造函数传递参数。
- 复制构造函数只能接受一个参数,既用来初始化派生类定义的成员,也将被传递给基类的复制构造函数。
- 基类的复制构造函数形参类型是基类对象的引用,实参可以是派生类对象的引用
析构函数
- 析构函数不被继承,派生类如果需要,要自行声明析构函数。
- 声明方法与无继承关系时类的析构函数相同。
- 不需要显式地调用基类的析构函数,系统会自动隐式调用。
- 先执行派生类析构函数的函数体,再调用基类的析构函数。
#include<iostream>
using namespace std;
class Base1 {
public:
Base1(int val) {
x = val;
cout << "Calling constructor of base1..." << endl;
}
Base1(Base1& a) {
x = a.x;
cout << "Calling copy constructor of base1..." << endl;
}
~Base1() {
cout << "Calling destructor of base1..." << endl;
}
private:
int x;
};
class Base2 {
public:
Base2(int val) {
y = val;
cout << "Calling constructor of base2..." << endl;
}
Base2(Base2& b) {
y = b.y;
cout << "Calling copy constructor of base2..." << endl;
}
~Base2() {
cout << "Calling destructor of base2..." << endl;
}
private:
int y;
};
class Derived:
public Base1, public Base2 {
public:
Derived(int val1, int val2, int val3) :
Base1(val1), Base2(val2) {
cout << "Calling constructor of derived..." << endl;
z = val3;
}
Derived(Derived& c) :
Base1(c), Base2(c) {
cout << "Calling copy constructor of derived..." << endl;
z = c.z;
}
~Derived() {
cout << "Calling destructor of derived..." << endl;
}
private:
int z;
};
int main() {
Derived d(1, 2, 2);
cout << "***********************" << endl;
Derived newd(d);
cout << "***********************" << endl;
return 0;
}
输出结果:
Calling constructor of base1...
Calling constructor of base2...
Calling constructor of derived...
Calling copy constructor of base1...
Calling copy constructor of base2...
Calling copy constructor of derived...
Calling destructor of derived...
Calling destructor of base2...
Calling destructor of base1...
Calling destructor of derived...
Calling destructor of base2...
Calling destructor of base1...