使用类来描述客观世界是C++典型特征,而类的继承可以实现对现有类的复用、扩展,或者进一步对现有类的行为和属性进行修改。继承产生的新类称为派生类(或子类),原有的类称为基类(或父类)。通过继承方式的运用能够大幅度减少代码量,提高编程效率。
一、继承的语法
class 子类:继承方式 父类
关于子类的继承方式,与父类中描述成员访问权限的关键字相同,而且与父类中成员的访问权限也密切相关:
a. public(公共继承)方式:这种方式下,父类中的公共成员到子类中仍为公共的;父类中的保护成员到子类中仍是保护的权限,子类中可以访问,子类外不可见;父类中的私有成员子类中不可访问。
b. protected(保护继承)方式:子类中可以访问父类中公共、保护性的成员,父类中的私有成员子类中不可访问。同时因为是保护继承,父类中公共成员也会变成保护的,子类外都不能访问了,都变成保护的了。但父类中私有的成员仍是私有,到了子类中不会变成保护的。
c. private(私有继承)方式:父类中除私有成员外,子类中皆可访问;但到了类外,父类中公共、保护成员会变成私有的,子类外都访问不到。
补充:子类继承父类实际是全面继承的,包含私有的成员属性都会被继承下去,只是访问不到。
二、继承中构造函数和析构函数的运行顺序
构造函数:先父类构造、后子类构造;析构函数:先子类析构、再父类析构。如果继承更为复杂,存在孙继承或重孙继承,构造函数和析构函数仍是这样的顺序,构造函数是自上而下,析构函数是自下而上。
三、子类中成员与父类中成员同名的处理
在子类中,不加修饰使用成员则调用的是子类中的成员,如需调用父类中的成员可以加上作用域,即(父类名::),实际上,无论是否存在重名,只要是使用父类中的成员则一律加上作用域是更好的做法,调用关系更为清晰,自己或他人看的也明白。
四、多继承
所谓多继承即一个子类继承自两个或两个以上的父类,语法是:
class 子类名: public 父类名1, private 父类名2, ... ...
这种情况下,更容易产生同名问题,要时刻想着加上作用域以示区分。多继承不是好的编程方式,能不使用尽量不使用。
五、用一个小程序对上面的内容做进一步说明(VS2022):
#include<iostream>
using namespace std;
int main() {
//一、继承语法举例
class myClass {
public:
int a = 5;
protected:
int b = 9;
private:
int c = 11;
};
//a.public方式继承情形 ********************
class myNewClass :public myClass {
public:
void myCout() {
cout << "public a=" << myClass::a << endl; //类内正常访问父类公开成员
cout << "protected b=" << myClass::b << endl; //类内正常访问父类保护成员
//cout << "private c=" << myClass::c << endl; //类内访问父类私有成员报错
}
};
myNewClass c1; //实例化子类对象
c1.myCout(); //调用子类成员函数
//类内访问运行结果:
// public a=5
// protected b=9
//类外访问情况:
cout << "类外访问父类中公开成员:a=" << c1.a << endl; //运行结果:类外访问父类中公开属性:a=5
//cout << "类外访问父类中保护成员:b=" << c1.b << endl; //报错
//cout << "类外访问父类中私有成员:c=" << c1.c<<endl; //报错
//b.protected继承情形 **********************
class myNewClass2 :protected myClass {
public:
void myCout() {
cout << "public a=" << myClass::a << endl; //类内正常访问父类公开成员
cout << "protected b=" << myClass::b << endl; //类内正常访问父类保护成员
//cout << "private c=" << myClass::c << endl; //类内访问父类私有成员报错
}
};
myNewClass2 c2;
c2.myCout();
//类内访问运行结果
//public a=5
//protected b = 9
//类外访问情况
//cout << "类外访问父类中公开属性:a=" << c2.a << endl; //报错
//cout << "类外访问父类中保护成员:b=" << c1.b << endl; //报错
//cout << "类外访问父类中私有成员:c=" << c1.c<<endl; //报错
//c.private继承情形 (略)
//二、关于继承中构造函数和析构函数的运行顺序
class grandeClass {
public:
grandeClass() {
cout << "祖构造函数已被调用"<<endl;
}
~grandeClass() {
cout << "祖析构函数已被调用" << endl;
}
};
class fatherClass :public grandeClass {
public:
fatherClass() {
cout << "父构造函数已被调用..."<<endl;
}
~fatherClass() {
cout << "父析构函数已被调用..." << endl;
}
};
class sonClass :public fatherClass {
public:
sonClass() {
cout << "子构造函数已被调用......" << endl;
}
~sonClass() {
cout << "子析构函数已被调用......" << endl;
}
};
//以上三个类存在一次继承关系,现在实例化子类对象,看一下构造与析构函数的运行顺序
sonClass* p=new sonClass; //在堆区创建一个sonClass对象并获得其指针,此时调用构造函数
delete p; //删除对象,此时调用析构函数
//运行结果:
//祖构造函数已被调用
//父构造函数已被调用...
//子构造函数已被调用......
//子析构函数已被调用......
//父析构函数已被调用...
//祖析构函数已被调用
//三、子类中成员与父类中成员名同名的处理
class father {
public:
string str = "这是父类中的str...";
};
class son:public father {
public:
string str = "这是子类中的str......";
};
son s;
cout << s.str << endl; //运行结果:这是子类中的str......
father f;
cout << f.str << endl; //运行结果:这是父类中的str...
//如不加作用域,则哪个类声明的对象就访问哪个类的成员
cout << s.father::str << endl; //这是父类中的str...
cout << s.son::str << endl; //这是子类中的str......
//加上作用域则按照作用域的指向访问,但只能是通过子类访问父类成员,倒过来不行
//四、多继承
class f1 {
public:
int a1=1;
};
class f2 {
public:
int a2=2;
};
class f3 {
public:
int a3 = 3;
};
class S :public f1, public f2, public f3 {
public:
void myPrint() {
cout << "f1中a1=" << f1::a1 << endl;
cout << "f2中a2=" << f2::a2 << endl;
cout << "f3中a3=" << f3::a3 << endl;
}
};
S s1;
s1.myPrint();
//运行结果:
// f1中a1 = 1
// f2中a2 = 2
// f3中a3 = 3
system("pause");
}