多态
多态基本概念
**多态的概念**:
通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态 。
多态定义以及实现
** 1..重写/覆盖 的要求**
重写/覆盖: 子类中有一个跟父类完全相同的虚函数,子类的虚函数重写了基类的虚函数
即:子类父类都有这个虚函数 + 子类的虚函数与父类虚函数的 函数名/参数/返回值 都相同 -> 重写/覆盖(注意:参数只看类型是否相同,不看缺省值)
**2.多态两个要求:**
1、被调用的函数必须是虚函数,子类对父类的虚函数进行重写 (重写:三同(函数名/参数/返回值)+虚函数)
2、父类指针或者引用去调用虚函数。
#include <iostream>
using namespace std;
class Person
{
public:
//constructor不能用虚函数关键字修饰
virtual void buyTicket()
{
cout << "100$" << endl;
}
};
class Student : public Person
{
public:
void buyTicket()
{
cout << "80$" << endl;
}
};
int main(int argc, const char *argv[])
{
Person p;
p.buyTicket();//
cout << "-------------" << endl;
Student s;
s.buyTicket();
cout << "-------------" << endl;
Person *p1 = &s;
p1->buyTicket();
Person &p2 = s;
p2.buyTicket();
cout << "-------------" << endl;
Person p3 = s;
p3.buyTicket();
return 0;
}
静态绑定和动态绑定
**静态绑定**:绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期
**动态绑定:**绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期
**代码实例:**
#include "iostream"
using namespace std;
class B{
public:
void DoSomething(){
cout << "B DoSomething()......\n";
}
virtual void vfun(){
cout << "B vfun()......\n";
}
};
class C: public B{
public:
void DoSomething(){ // 首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导致名称隐藏;这里只是为了说明动态绑定和静态绑定才这样使用。
cout << "C DoSomething().....\n";
}
virtual void vfun(){
cout << "C vfun()......\n";
}
};
class D:public B{
public:
void DoSomething(){
cout << "D DoSomething().....\n";
}
virtual void vfun(){
cout << "D vfun()......\n";
}
};
int main(){
// 静态绑定
D *pD = new D();
B *pB = pD;
pD->DoSomething();
pB->DoSomething();
// 动态绑定
pD->vfun();
pB->vfun();
return 0;
}
注意
当缺省参数和虚函数一起出现的时候情况有点复杂,极易出错。我们知道虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的
#include "iostream"
using namespace std;
// 对象的动态与静态类型
class B{
public:
void DoSomething(){
cout << "B DoSomething()......\n";
}
virtual void vfun(){
cout << "B vfun()......\n";
}
// 缺省参数和虚函数一起出现,是静态绑定!
virtual void func(int i = 20){
cout << "B func()......\n";
}
};
class C: public B{
public:
void DoSomething(){ // 首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导致名称隐藏;这里只是为了说明动态绑定和静态绑定才这样使用。
cout << "C DoSomething().....\n";
}
virtual void vfun(){
cout << "C vfun()......\n";
}
virtual void func(){
cout << "C func()......\n";
}
};
class D:public B{
public:
void DoSomething(){
cout << "D DoSomething().....\n";
}
virtual void vfun(){
cout << "D vfun()......\n";
}
virtual void func(){
cout << "D func()......\n";
}
};
int main(){
// 缺省参数和虚函数一起出现,是静态绑定!
D *pD = new D();
B* pB = pD;
pD->func();
pB->func();
return 0;
}
虚函数与动态多态(上面介绍了一些)
重写的特点
1.与基类的虚函数有相同的参数个数
2.与基类的虚函数有相同的参数类型
3.与基类的虚函数有相同的返回值类型
4.不同作用域
5.基类必须有virtual关键字不能有static
6.重写函数访问限定符可以不用相同
**例外: 协变和析构函数可以不尊崇上面的规则**
**协变(返回值为对象引用或者指针)**
指针
class A {};
class B :public A {};
class Person
{
public:
virtual A* func()
{
cout << "virtual A* func()" << endl;
return new A;
}
};
class Student : public Person
{
public:
virtual B* func()
{
cout << "virtual B* func()" << endl;
return new B;
}
};
引用
class Human
{
public:
virtual Human& print()
{
cout << "i am a human" << endl;
return *this;
}
};
class Student : public Human
{
public:
virtual Student& print()
{
cout << "i am a student" << endl;
return *this;
}
};
析构函数的重写
class Human
{
public:
~Human()
{
cout << "~Human()" << endl;
}
};
class Student : public Human
{
public:
~Student()
{
cout << "~Student()" << endl;
}
};
int main()
{
Human* h = new Student;
delete h;
return 0;
}
final和override关键字
final
使用final的虚函数不能被重写(c++11)
class Human
{
public:
virtual void print() final
{
cout << "i am a human" << endl;
}
};
class Student : public Human
{
public:
virtual void print()
{
cout << "i am a student" << endl;
}
};
override
override关键字是用来检测派生类虚函数是否构成重写的关键字
class A
{
public:
virtual void func() {}
};
class B : public A
{
public:
//未重写则报错
virtual void func() override {};
};
覆盖,重载,隐藏
当用virtual修饰的时候,类的实例化就会产生一个虚表,专门放虚函数,当子类继承父类后,重写虚函数的时候,子类的对象实例化就会覆盖原来的虚函数,所以也就是上面的子类对象在调用的时候,总是调用子类实现的成员函数,当父类的指针或引用指向子类对象时候如上所示!
动态原理和虚函数表
#include <iostream>
using namespace std;
class A
{
public:
virtual void show()
{
cout << "A show" << endl;
}
virtual void show2()
{
cout << "A show2" << endl;
}
};
class B : public A
{
public:
virtual void show2()
{
cout << "B show2" << endl;
}
};
typedef void (*Func)();
int main(int argc, const char *argv[])
{
A *a = new B;
a->show();
a->show2();
cout << "-------------" << endl;
cout << "virtual_Pointer Address is " << (long *)a << endl;
cout << "virtual_table Address is " << (long *)*(long *)a << endl;
cout << "virtual_table func1 Address is " << (long *)*(long *)a << endl;
cout << "virtual_table func2 Address is " << (long *)*(long *)a + 1 << endl;
cout << "virtual_table real func1 Address is " << (long*)((long *)*(long *)a) << endl;
cout << "virtual_table real func2 Address is " << (long *)((long *)*(long *)a + 1) << endl;
Func fa = (Func)*((long *)*(long *)a);
fa();
cout << "---------" << endl;
B b;
A &a1 = b;
cout << "virtual_Pointer Address is " << (long *)&a1 << endl;
cout << "virtual_table Address is " << (long *)*(long *)&a1 << endl;
cout << "virtual_table func1 Address is " << (long *)*(long *)&a1 << endl;
cout << "virtual_table func2 Address is " << (long *)*(long *)&a1 + 1 << endl;
cout << "virtual_table real func1 Address is " << (long*)((long *)*(long *)&a1) << endl;
cout << "virtual_table real func2 Address is " << (long *)((long *)*(long *)&a1 + 1) << endl;
Func fa1 = (Func)*((long *)*(long *)&a1);
fa1();
return 0;
}
抽象类与纯虚函数
#include <iostream>
using namespace std;
//如果子类没有实现抽象类的所有虚函数,那么子类也会变成抽象类
class Base
{
public:
virtual void get_area() = 0;
};
class Circle : public Base
{
public:
Circle(int r)
{
this->r = r;
}
void get_area()
{
cout << "Circle area is: " << 3.14 * r * r << endl;
}
private:
int r;
};
class Rect : public Base
{
public:
Rect(int length, int height)
{
this->length = length;
this->height = height;
}
void get_area()
{
cout << "Rect area is: " << length * height << endl;
}
private:
int length;
int height;
};
int main(int argc, const char *argv[])
{
Circle c(4);
c.get_area();
Rect r(10,10);
r.get_area();
Base *b = &c;//抽象类只能用指针和引用,不能直接实例化
b->get_area();
Base &rb = r;
rb.get_area();
return 0;
}