1.虚函数实现多态
//虚函数:
//当虚函数的声明和定义分离时时候,声名一定要加 virtual ,但定义不需要加 virtual
//多态
//不同对象做同一件事,多种形态,结果不一样
/*
#include<iostream>
using namespace std;
class Person {
public:
//虚函数
virtual void BuyTicket() { cout << "Person->买票-全价" << endl; }
};
class Student : public Person {
public:
virtual void BuyTicket() { cout << "Student->买票-半价" << endl; }
};
// 多态:指向谁,调用谁的虚函数
// 多态的实现:
// 1、父子类完成虚函数重写(三同:函数名、参数、返回值)
// (父类函数加 virtual 修饰,子类可以不加,但建议加上)
// 2、父类的指针或者引用 去调用虚函数
void Func(Person* p)
{
p->BuyTicket();//指针调用虚函数
// p.BuyTicket() 寄,没有多态
}
int main()
{
Person ps;
Student st;
Func(&ps);
Func(&st);
return 0;
}
2.协变
//协变: 1.基类与派生类虚函数的 返回值类型 不同
// 但 返回值是父子类指针关系的引用
// 2.析构函数的重写
/*
#include<iostream>
using namespace std;
class A {};
class B : public A {};
class Person {
public:
virtual A* BuyTicket()
//virtual Person* BuyTicket()
{
cout << "Person->买票-全价" << endl;
return nullptr;
}
virtual ~Person()
{
cout << "~Person()" << endl;
}
};
class Student : public Person {
public:
virtual B* BuyTicket() //返回值不同构成协变(返回值一定是父子类指针)
//virtual Student* BuyTicket()
//~Student() 子类重写虚函数 可以不加 virtual ,效果一样
{
cout << "Student->买票-半价" << endl;
return 0;
}
virtual ~Student()//析构函数的函数名相同,构成重写
{
cout << "delete[]" << _ptr << endl;
delete[] _ptr;
cout << "~Student()" << endl;
}
private:
int* _ptr = new int[10];
};
void Func(Person* p)
{
p->BuyTicket();
}
int main()
{
//Person ps;// ~Peron()
//Student st;// ~Student() ~Peron() 析构; 先子后父
// !!!!!!!!!!重点!!!!!!!!!!!!!
Person* p1 = new Person;
Person* p2 = new Student;
// 析构函数 + operator delete(p1)
delete p1;// ~Person() 父类析构
delete p2;// ~Student()
// delete[]010EFAB8 ~Student() ~Person() 子类析构+父类析构
// 结论: 建议析构函数定义为虚函数,防止发生 内存泄漏
// 不加虚函数析构: ~Person() ~Person() 调用两次析构, 子类空间未释放
return 0;
}
3.多态的底层
#include<iostream>
using namespace std;
class Person {
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }
private:
int _i = 1;
};
class Student : public Person {
public:
virtual void BuyTicket() { cout << "买票-半价" << endl; }
int _j = 2;
};
void Func(Person* p)
{
p->BuyTicket();
}
int main()
{
Person Mike;
Func(&Mike);
Person p1;
Func(&p1);
//同一类型的虚表是一样的
Student Johnson;
Func(&Johnson);
//若满足多态,系统就去指向对象的虚表中找对应的虚函数调用
return 0;
}
4.抽象类
// 多态调用: 运行时,到指向对象的虚表中找虚函数调用,指向父类调用父类的虚函数 ,指向子类调用子类的虚函数
// 普通调用: 编译时,根据调用对象类型,去调用它的函数
// 虚表中存的仅仅是虚函数的地址
// 虚表存放在 常量区 !!!!!!
// 同类型对象共用同一个虚表
/*
#include<iostream>
using namespace std;
//抽象类: (类中至少有一个纯虚函数)
// 1.不能实例化对象(但能使用指针)
// 2.间接强制 子类 重写 虚函数
// 3,不能作为 函数返回值、函数参数
class Car
{
public:
//纯虚函数 ( 虚函数后加 =0)
virtual void Drive() = 0;
};
class Benz :public Car// 继承抽象类 也是 抽象类
{
public:
//纯虚函数被继承
};
class BMW :public Car
{
public:
virtual void Drive()
// 完成纯虚函数重写
{
cout << "BMW-Drive()" << endl;
}
};
int main()
{
// Car c; //error
//Benz b; //error
BMW B;
Car* ptr = &B;// 使用父类指针调用函数,实现多态
ptr->Drive();
return 0;
}
例题: 构造顺序
#include<iostream>
using namespace std;
class A {
public:
A(const char* s)
{ cout << s << endl; }
~A() {}
};
class B :virtual public A
{
public:
B(const char* s1, const char* s2)
:A(s1)
{ cout << s2 << endl; }
};
class C :virtual public A
{
public:
C(const char* s1, const char* s2)
:A(s1)
{ cout << s2 << endl; }
};
class D :public B, public C
{
public:
D(const char* s1, const char* s2, const char* s3, const char* s4)
:B(s1, s2) //A B
, C(s1, s3) //A C
, A(s1) //A (A 会在 此处 构造)
// A 只会被初始化 一次,菱形虚拟继承只有 一个 A
// !!!!!!!!!!!!!!!!
// 初始化列表 的 初始化顺序 按照 成员声名的顺序 ,而不是 出现的顺序
//所以构造顺序 A B C D
{ cout << s4 << endl;}
};
int main()
{
D* p = new D("class A", "class B", "class C", "class D");
// class A, class B, class C, class D
delete p;
return 0;
}