C++中的多态
1、多态的概念
2、多态的定义及实现
3、抽象类
4、c++中的override 和 final
5、多态的原理
6、单继承和多继承关系中的虚函数表
——————————————————————————————
前言
需要声明的,本文代码及解释都是在vs2013下的x86程序中,涉及的指针都是4bytes。如果要其他 平台下,部分代码需要改动。比如:如果是x64程序,则需要考虑指针是8bytes问题等等
1、多态的概念
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完
成时会产生出不同 的状态。
2、多态的定义及实现
#include <iostream>
using namespace std;
#include <string>
// 买票
// 普通人
class Person
{
public:
Person(const string& name, const string& gender, int age)
: _name(name)
, _gender(gender)
, _age(age)
{}
// 虚函数
virtual void BuyTicket() // 基类必须为虚函数
{
cout << "全价票" << endl;
}
protected:
string _name;
string _gender;
int _age;
};
class Student : public Person
{
public:
Student(const string& name, const string& gender, int age, int stuId)
: Person(name, gender, age)
, _stuId(stuId)
{}
virtual void BuyTicket()
{
cout << "半价票" << endl;
}
protected:
int _stuId;
};
class Soilder : public Person
{
public:
Soldier(const string& name, const string& gender, int age, const string& rank)
: Person(name, gender, age)
, _rank(rank)
{}
void BuyTicket()
{
cout << "免费" << endl;
}
protected:
string _rank;
};
void TestBuyTicket(Person& p) //基类引用接收参数
{
p.BuyTicket();
}
/* 代码冗余
void TestBuyTicket(Person& p)
{
p.BuyTicket();
}
void TestBuyTicket(Student& p)
{
p.BuyTicket();
}
void TestBuyTicket(Soldier& p)
{
p.BuyTicket();
}
*/
int main()
{
Person p("Peter", "男", 18);
Student st("小帅", "女", 19, 1000);
Soldier so("威武", "男", 23, "班长");
TestBuyTicket(p); Person& p = p
TestBuyTicket(st); Person& p = st
TestBuyTicket(so); Person& p = so
return 0;
}
必须通过基类的指针或引用来调用---->继承方式必须public 因为:基类引用需要引用到子类对象。
多态的体现:代码编译时,不能确定到底调用那个类的虚函数。
在代码运行时,根据p所指向的实际对象选择调用对应类的虚函数
如果多态的实现条件没有完全满足:
1. 重写失败(1、基类函数不是虚函数 2、函数原型不一致)
2. 没有通过基类的指针或者引用调用虚函数
3、抽象类
抽象类--包含有纯虚函数的类
特性:不能实例化对象,但可以创建该类的指针(引用)
作用:规范后序接口
#include <string>
class WC
{
public:
void GoToManRoom()
{
cout << "go to left" << endl;
}
void GoToWoManRoom()
{
cout << "go to right" << endl;
}
};
class Person
{
public:
// 纯虚函数
virtual void GoToWC(WC& wc) = 0;
string _name;
int _age;
};
class Man : public Person
{
public:
void GoToWC(WC& wc)
{
wc.GoToManRoom();
}
};
class Woman : public Person
{
public:
void GoToWC(WC& wc)
{
wc.GoToWoManRoom();
}
};
// Monster类也是抽象类,因为该类没有重写基类中的纯虚函数
class Monster : public Person
{};
#include <windows.h>
#include <time.h>
void TestWC(int n)
{
WC wc;
srand(time(nullptr));
for (int i = 0; i < n; ++i)
{
Person* pGuard; // 厕所管理员
if (rand() % 2 == 0)
pGuard = new Man;
else
pGuard = new Woman;
pGuard->GoToWC(wc);
delete pGuard;
Sleep(1000);
}
}
int main()
{
Person* p;
//Monster m;
TestWC(10);
return 0;
}
4、c++中的override 和 final
C++11:
override: 只能修饰派生类的虚函数
作用:让编译器帮助用户检测派生列中某个虚函数是否重写了基类的那个虚函数
class Base
{
public:
virtual void TestFunc()
{
cout << "Base::TestFunc()" << endl;
}
int _b;
};
class Derived : public Base
{
public:
virtual void TestFunc()override
{
cout << "Derived::TestFunc()" << endl;
}
int _d;
};
void TestVirtualFunc(Base* pb)
{
pb->TestFunc();
}
int main()
{
Base b;
Derived d;
TestVirtualFunc(&b);
TestVirtualFunc(&d);
return 0;
}
final: 修饰类--->表示该类不能被继承
修饰虚函数函数--->
class Base
{
public:
virtual void TestFunc()const
{
cout << "Base::TestFunc()" << endl;
}
int _b;
};
// 假设在Derived的子类中,不想让其子类重写TestFunc的虚函数
// C++98中做不到
// C++11:提供的final的关键字可以作用
// final修饰虚函数,表明该虚函数不想让其在子类中被重写(一般final修饰子类的虚函数)
class Derived : public Base
{
public:
virtual void TestFunc()const override
{
cout << "Derived::TestFunc()" << endl;
}
int _d;
};
5、多态的原理
//如果一个类中包含有虚函数,类大小会多四个字节
//编译器会给该类生成一个默认的构造函数,该4个字节是在构造函数中填充的
class Base
{
public:
// 若显示定义默认构造函数
// Base()
// {}
// 此时构造函数什么都没有做,那么该4个字节,是否还会填充?
// 仍然填充,会多出4个字节
virtual void TestFunc3()
{
cout << "Base::TestFunc3()" << endl;
}
virtual void TestFunc1()
{
cout << "Base::TestFunc1()" << endl;
}
virtual void TestFunc2()
{
cout << "Base::TestFunc2()" << endl;
}
int _b;
};
int main()
{
cout << sizeof(Base) << endl; // 8字节
Base b;
b._b = 1;
return 0;
}
6、单继承和多继承关系中的虚函数表
带有虚函数的多继承派生类的对象模型
// 8
class B1
{
public:
virtual void TestFunc1()
{
cout << "B1::TestFunc1()" << endl;
}
virtual void TestFunc2()
{
cout << "B1::TestFunc2()" << endl;
}
int _b1;
};
// 8
class B2
{
public:
virtual void TestFunc3()
{
cout << "B2::TestFunc3()" << endl;
}
virtual void TestFunc4()
{
cout << "B2::TestFunc4()" << endl;
}
int _b2;
};
// 20个字节
class D : public B1, public B2 //
{
public:
virtual void TestFunc1()// 重写
{
cout << "D::TestFunc1()" << endl;
}
virtual void TestFunc4()// 重写
{
cout << "D::TestFunc4()" << endl;
}
virtual void TestFunc5()// 重写
{
cout << "D::TestFunc5()" << endl;
}
int _d;
};
typedef void(*PVFT)();
void PrintVFT1(B1& b, const string& str)
{
cout << "D重写B1基类的虚表" << endl;
PVFT* pVFT = (PVFT*)(*(int*)&b);
while (*pVFT)
{
(*pVFT)();
++pVFT;
}
cout << endl;
}
void PrintVFT2(B2& b, const string& str)
{
cout << str << endl;
PVFT* pVFT = (PVFT*)(*(int*)&b);
while (*pVFT)
{
(*pVFT)();
++pVFT;
}
cout << endl;
}
int main()
{
cout << sizeof(D) << endl;
D d;
d._b1 = 1;
d._b2 = 2;
d._d = 3;
PrintVFT1(d, "D重写B1基类的虚表");
PrintVFT2(d, "D重写B2基类的虚表");
return 0;
}