class Person
{
public:
//虚函数:virtual + 正常的函数定义
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
//一般基类的析构函数都定义为虚函数,避免内存泄漏的问题
virtual ~Person()
{
cout << "~Person()" << endl;
}
};
class Student : public Person
{
public:
//虚函数重写:子类定义了一个和父类接口完全相同的函数
//重写的虚函数:函数名,参数列表,返回值类型和父类对应的函数完全一致
virtual void BuyTicket()
{
cout << "买票-半价" << endl;
}
//即使前面不加virtual 也会有虚函数属性
//都是虚函数,在底层和父类析构函数名相同,构成虚函数重写,构成多态
~Student()
{
delete[100] ptr;
cout << "~Student()" << endl;
}
protected:
char* ptr = new char[100];
};
//多态:看对象
void fun(Person& p)
{
p.BuyTicket();
}
//非多态:看类型
void fun2(Person p)
{
p.BuyTicket();
}
void test()
{
Person p;
Student s;
fun(p);
fun(s);
//构成多态,指向子类对象,先调用子类的析构,再调用父类析构
Person* p1 = new Student;
delete p1;
Student* p2 = new Student;
delete p2;
}
int main()
{
test();
return 0;
}
协变:返回值类型可以不同,但是必须是有继承关系的指针/引用
class A
{};
class B: public A
{};
class Person
{
public:
//虚函数:virtual + 正常的函数定义
//协变:返回值类型可以不同,但是必须是有继承关系的指针/引用
virtual A* BuyTicket()
{
cout << "买票-全价" << endl;
return new A;
}
};
class Student : public Person
{
public:
//虚函数重写:子类定义了一个和父类接口完全相同的函数
//重写的虚函数:函数名,参数列表,返回值类型和父类对应的函数完全一致
virtual B* BuyTicket()
{
cout << "买票-半价" << endl;
return new B;
}
};
final 在父类中使用:表示父类的虚函数不能再被子类重写
虚函数+final:此函数不能被子类重写
class A
{
//子类不能再对该函数进行重写
virtual void fun() final
{
cout << "A::fun()"<<endl;
}
}
override 通常在子类中使用:表示会自动检查必须重写父类的一个函数
虚函数+override:强制重写父类的一个虚函数
class A
{
public:
virtual void fun()
{
cout << "A::fun()"<<endl;
}
}
class B:public A
{
public:
virtual void fun() override
{
cout<<"B::fun()"<<endl;
}
}
接口继承和实现继承:
普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。
获取虚表地址
//定义vfptr为函数指针类型
typedef void(*vfptr)();
//vfTable代表虚表指针,指向虚表的首元素地址,为二级指针
//虚表内存放的都是虚函数指针
void printVTable(vfptr vfTable[])
{
cout << "虚表地址:"<< vfTable << endl;
//定义一个二级指针fptr也指向虚表首元素地址
vfptr* fptr = vfTable;
//做解引用,拿到一个虚函数指针
while(*fptr != nullptr)
{
//虚函数指针(),虚函数指针指向的函数开始执行
(*fptr)();
//往下移动,指向下一个虚函数指针
++fptr;
}
}
void test()
{
Person p;
cout << "Person vfptr: ";
vfptr* vftable = (vfptr*)(*(int*)&p);
printVtable(vftable);
}
多继承: