c++第8天--虚继承与多态
本讲内容:
- 认识什么是虚继承
- 什么是虚函数
- 多态的含义
综上:虚继承就是
//虚继承就是c++为了解决多继承中的菱形继承问题而引入的一种特殊的继承方式
//虚继承就是让派生类只保留一份共同基类的成员,进而避免重复和二义性
虚继承的语法:
class A {...}
class B : virtual public A {...}
class C : virtual public A {...}
class D : public B, public C {...}
这样D对象中会有一份A的成员
虚继承就是为了解决多继承时“同一个祖先类会被继承多份”的问题。
比如:
- 有一个A类,B和C都继承A,D又同时继承B和C。
- 如果不用虚继承,D里面会有两份A的内容(重复了)。
- 用了虚继承,D里面只会有一份A的内容(不重复)。
一句话总结: 虚继承就是让多继承时,最上面的公共基类只保留一份,避免重复和混乱。
#include<iostream>
using namespace std;class A{
public:int x;A() : x(100) {}
};class B : virtual public A {};
class C : virtual public A {};
class D : public B,public C {};int main()
{D d;d.x = 200; //不会有二义性cout << d.x << endl;return 0;
}
这便就是一个典型的菱形继承问题。
下面就是一个虚继承的例子
//虚继承就是为了解决多继承时“同一个祖先类会继承多份”的问题
//下面就是一个典型的虚继承的实例
#include<iostream>
using namespace std;class Furniture{
public:Furniture(string wood);
protected:string _wood;
};Furniture :: Furniture(string wood)
{_wood = wood;
}class Sofa : virtual public Furniture{
public:Sofa(float length,string wood);
protected:float _length;
};Sofa::Sofa(float length,string wood) : Furniture(wood),_length(length) {}
//这一行的意思就是通过 Sofa类的构造函数来实现,重点在于初始化列表部分
//Furniture(wood)这里表示在构造Sofa对象的时候,先调用虚基类Furniture,并把wood参数传递给他
//_length(length)这里表示用length参数初始化Sofa类自己的成员class Bed : virtual public Furniture{
public:Bed(float width,string wood);
protected:float _width;
};Bed :: Bed(float width,string wood): Furniture(wood),_width(width) {}class Sofabed : public Sofa,public Bed{
public:Sofabed(float length,string wood,float width);void getSize();
};Sofabed::Sofabed(float length,string wood,float width) : Sofa(length,wood),Bed(width,wood),Furniture(wood) {}
void Sofabed :: getSize(){cout << "沙发床长" << _length << "m" << endl;cout << "沙发床宽" << _width << "m" << endl;cout << "沙发床材质为" << _wood << endl;
}int main()
{Sofabed sbed(1.8,"梨木",1.5);sbed.getSize();return 0;
}
现在我们再展开说一下多态
多态是什么意思呢?
这是面向对象编程中的三大特性之一,意思就是“同一种操作作用于不同的对象,可以有不同的表现。
简单的来说,就是用父类指针/引用指向子类对象,通过虚函数调用,实际执行的是之类的实现
那么多态的三要素是:
1.继承,必须有基类与派生类
2.虚函数,基类中有virtual声明的成员函数
3.父类指针/引用:用基类指针或引用指向派生类对象
#include <iostream>
using namespace std;class Animal {
public:virtual void speak() { // 虚函数cout << "动物叫" << endl;}
};class Dog : public Animal {
public:void speak() override { // 重写cout << "狗叫:汪汪" << endl;}
};void makeSound(Animal* a) {a->speak(); // 多态:实际调用的是对象的真实类型的方法
}int main() {Dog d;makeSound(&d); // 输出:狗叫:汪汪return 0;
}
虚函数
通过给函数加上virtual关键字,使成员函数成为虚函数,类中会增加了虚函数表指针的成员,虚函数表中会保存自己类的虚成员函数的地址,在通过指针或引用访问成员函数时,会先到虚函数表查找有无该成员函数,如果有就调用,没有的话就再去找其他的成员函数。
通过这种机制实现基类指针、引用调用实际指向的派生类的成员函数
多态的难点在于理解与运用
//虚函数
//虚函数式c++中实现多态的关键
#include<iostream>
using namespace std;class Person
{
public:virtual void work() {cout << "工作" << endl;}
};class Worker : public Person
{
public:void work() {cout << "工人生产" << endl;}
};class Farmer : public Person
{
public:void work() {cout << "修理" << endl;}
};class Teacher : public Person
{
public:void work() {cout << "教与学" << endl;}
};void dowork(Person& p)
{p.work();
}int main()
{//数组:把上面所有人放进去,循环调用他们的work()Person* p[3];p[0] = new Worker();p[1] = new Farmer();p[2] = new Teacher();for(int i = 0;i < 3;++i)dowork(*p[i]);for(int i = 0;i < 3;++i)delete p[i];return 0;
}