一、基础语法
当我们在设计类时,可能会遇到多个类具有相同的属性,为了避免写重复的代码,我们可以将这些重复的属性写在一个类A中,让具有这些属性的类直接继承A。
语法:class 子类 : 继承方式(如public等) 父类
示例
//公共属性(父类,也称为基类)
class father
{
int a;
int b;
}
//子类,也称为派生类
class son : public father
{
int c;
}
/*上述代码等效于
class son
{
int a;
int b;
int c;
}*/
二、继承方式
类的继承方式一共有三种,分别对应类的三种访问权限:public,protected,private。需要注意的是,类在继承时,并不会把属性的访问权限也继承了。下面这张表可以清晰反应出父类中不同的访问权限在不同的继承方式下对应的子类中的访问权限。
public | protected | private | |
---|---|---|---|
public继承 | public | protected | 无法访问 |
protected继承 | protected | protected | 无法访问 |
private继承 | private | private | 无法访问 |
注意:虽然子类无法访问父类中的私有成员,但其依然时被子类继承了,只是被编译器隐藏了而访问不到。
三、构造函与析构函数的调用顺序
在继承中父类的构造函数比子类先调用,而析构函数的顺序相反(可参考对象与对象成员的函数调用顺序)。
四、继承同名成员处理方式
当父类与子类中出现同名成时,处理方式如下:
1.调用子类同名成员,直接访问即可。
2.调用父类同名成员,需要加作用域。
示例
class father
{
int a;
}
class son : public father
{
int a;//与父类成员同名
}
int main()
{
son p;
//访问子类成员
p.a = 100;
//访问父类成员
p.father::a = 200;//加上作用域father
}
上述代码距离说明了同名变量的处理方法,而同名函数的处理方法也是一样的。需要注意的是,当我们访问子类同名函数时,父类中的同名函数会被隐藏,其重载函数也会被隐藏。
示例
class father
{
func()//父类同名函数
{
cout << "father.func()" << endl;
}
func(int a)//父类重载函数
{
cout << "father.func(int a)" << endl;
}
}
class son : public father
{
func()//子类同名函数
{
cout << "son.func" << endl;
}
}
int main()
{
son p;
/*不能通过调用子类函数不能调用父类中的重载函数
p.func(10);错误*/
//可以通过加作用域来调用
p.father::func(10);//正确
}
五、继承同名静态函数处理方式
继承中同名的静态成员与非静态成员的处理方式基本一致,只是比非静态成员多一种处理方式:通过类名调用。
示例
class father
{
static int a;
}
int father::a = 100;
class son : public father
{
static int a;
}
int son::a = 200;
int main()
{
son p;
//通过对象名调用
cout << p.a << endl;//子类
cout << p.father::a << endl;//父类
//通过类名调用
cout << son::a << endl;//子类
cout << son::father::a << endl;/父类
}
六、多继承语法
c++允许一个类继承多个类,但是一般不推荐使用,因为其有两个缺点:
1.容易出现重名,可以用上述处理重名的方法解决。
2.棱形继承问题(即b类和c类都继承了a类,而d类继承了b、c两个类,这样a类就被继承了两份,而实际上只需要一份就可以了),可以利用虚继承来访问。
示例
class base1
{
int a;
}
//继承前加virtual关键字变为虚继承
class base2 : virtual public base1{}
class base3 : virtual public base1{}
class son : public base2,public base3//此时由于base2、base3为虚继承,所以son中只继承了一份base1
{
int b;
}