一、继承的概念
继承是面向对象复用的重要手段。通过继承定义一个类,继承是类型之间的关系建模,共享公有的东西,实现各本质不同的东西。
二、三种继承方式
三种继承方式为:public(公有)、protected(私有)、private(保护)
继承方式 | 基类的public成员 | 基类的protected成员 | 基类的private成员 |
public继承 | 仍为public成员 | 仍为protected成员 | 不可见 |
protected继承 | 变为protected成员 | 变为protected成员 | 不可见 |
private继承 | 变为private成员 | 变为private成员 | 不可见 |
注意:使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,最好显示的写出继承方式。
三、继承的格式
单继承:一个子类只有一个直接父类
class <派生类类名> :<继承方式> <基类类名>
{
<新定义的类成员>
}
多继承:一个子类有两个或两个以上直接父类
class <派生类类名> :<继承方式> <基类类名>,<继承方式> <基类类名> ...
{
<新定义的类成员>
}
子类(即派生类)的构成:自定义的成员和继承来的成员
代码验证
class Base //父类
{
public:
void Display()
{
cout << "Display()" << endl;
}
public:
int _age;
};
class Derive:public Base //子类
{
public:
void fun()
{}
public:
int _num;
};
int main()
{
Base b1;
b1._age = 1;
Derive d1;
d1._num = 2;
d1._age = 3;
return 0;
}
1.子类对象可以赋值给父类对象(切片/切割)
2.父类对象不能复制给子类对象
3.父类的指针/引用可以指向子类对象
4.子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
虚函数:类的成员函数前面家virtual关键字。
虚函数重写:当在子类中定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写了父类的这个虚函数。
多态:当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数
class Person
{
public:
virtual void BuyTIckets()
{
cout << "买票" << endl;
}
};
class Student :public Person
{
public:
virtual void BuyTIckets()
{
cout << "买半价票" << endl;
}
};
void Fun(Person& p)
{
p.BuyTIckets();
}
int main()
{
Person p;
Student s;
Fun(p); //调用父类
Fun(s); //调用子类
}
总结:
1.派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同(协变除外)
2.基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
3.只有类的成员函数才能定义为虚函数。
4.静态成员函数不能定义为虚函数。
5.如果在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual。
6.构造函数不能为虚函数。
7.不要在构造函数和析构函数里面调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会发生未定义的行为。
纯虚函数:
在成员函数的形参后面加上=0,则成员函数为纯虚函数。
包含纯虚函数的类叫抽象类(接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。
六、友元与继承
友元关系不能继承,即基类友元不能访问子类私有和保护成员。
七、静态成员与继承
基类定义了static成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例。
八、重载、重写(覆盖)和重定义(隐藏)的区别:
重载:1.在同一作用域
2.函数名相同/参数不同
3.返回值可以不同
重写:1.不在同一作用域(分别在基类和派生类)
2.函数名相同/参数相同/返回值相同(协变例外)
3.基类函数必须有virtual关键字
4.访问修饰符可以不同
隐藏:1.在不同作用域(分别在基类和派生类)
2.函数名相同
3.在基类和派生类中只要不构成重写就是重定义。