一、 运行时多态
struct Test1 { virtual void vfunc() {...}};
struct Test2: public Test1 { virtual void vfunc() {...}};Test2 testb;Test1 testc=testb; // 非多态
Test* testd=&testb; // 多态
为什么上面一个是多态,一个不是多态?
因为第一个转换的对象之间的转换(虚表变了),第二个是指针的重新解析(虚表没有变)
#include <iostream>
#include <typeinfo>class A
{
public:A(){data1_ = new int();data2_ = new int();}virtual void vAfunc1() { std::cout << "A::vAfunc1()" << std::endl; };virtual void vAfunc2() { std::cout << "A::vAfunc2()" << std::endl; };void func1() { std::cout << "A::func1()" << std::endl; };void func2() { std::cout << "A::func2()" << std::endl; };virtual ~A(){std::cout << "A::~A" << std::endl;delete data1_;delete data2_;}private:int *data1_{};int *data2_{};
};class B : public A
{
public:B(){data3_ = new int();}virtual void vAfunc1() override { std::cout << "B::vAfunc1()" << std::endl; };virtual void vBfunc1() { std::cout << "B::vBfunc1()" << std::endl; };virtual void vBfunc2() { std::cout << "B::vBfunc2()" << std::endl; };void func2() { std::cout << "B::func2()" << std::endl; };virtual ~B(){std::cout << "B::~B" << std::endl;delete data3_;}private:int *data3_{};
};
当你通过基类指针或引用删除一个派生类对象时,如果没有虚析构函数,编译器只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类中的资源无法正确释放,从而引发资源泄漏。
二、RTTI
由于多态的存在,一个函数的传入参数如果是一个父类指针(引用),有时候我们需要获得参数到底是哪一个子类。可以通过typeinfo来进行查询
// 方式1
std::type_info *base_type = (std::type_info *)*((int64_t *)*(int64_t *)(&a) - 1);
std::cout << "typeinfo is:" << base_type->name() << std::endl;
// 方式2
std::cout << "the result of typeid(Base).name():" << typeid(A).name() << std::endl;
2.1 typeid操作符,用于返回指针和引用所指向的实际类型
#include <iostream>
#include <typeinfo>class A
{
public:A(){data1_ = new int();data2_ = new int();}virtual void vAfunc1() { std::cout << "A::vAfunc1()" << std::endl; };virtual void vAfunc2() { std::cout << "A::vAfunc2()" << std::endl; };void func1() { std::cout << "A::func1()" << std::endl; };void func2() { std::cout << "A::func2()" << std::endl; };virtual ~A(){std::cout << "A::~A" << std::endl;delete data1_;delete data2_;}private:int *data1_{};int *data2_{};
};class B : public A
{
public:B(){data3_ = new int();}virtual void vAfunc1() override { std::cout << "B::vAfunc1()" << std::endl; };virtual void vBfunc1() { std::cout << "B::vBfunc1()" << std::endl; };virtual void vBfunc2() { std::cout << "B::vBfunc2()" << std::endl; };void func2() { std::cout << "B::func2()" << std::endl; };virtual ~B(){std::cout << "B::~B" << std::endl;delete data3_;}private:int *data3_{};
};class C : public A
{
public:C(){data4_ = new int();}virtual void vAfunc1() override { std::cout << "C::vAfunc1()" << std::endl; };void func3() { std::cout << "C::func3()" << std::endl; };virtual ~C(){std::cout << "C::~C" << std::endl;delete data4_;}private:int *data4_{};
};void test(A *a)
{if (typeid(*a) == typeid(A)){A *pa = reinterpret_cast<A *>(a);pa->func1();}if (typeid(*a) == typeid(B)){B *pb = reinterpret_cast<B *>(a);pb->func2();}if (typeid(*a) == typeid(C)){C *pc = reinterpret_cast<C *>(a);pc->func3();}
}int main()
{A *base = &b;test(base);C c;base = &c;test(base);return 0;
}
-
typeid返回的std::type_info删除了靠北构造,所以只能接收指针/引用
- typeid的返回值会忽略cv限定符
2.2 dynamic_cast<type*>(e) 将基类型的指针或引用安全的转换为派生类指针或引用
struct Base{ 存在虚函数 }
struct A : public Base { ... }A a;
Base b;Base* b_ptr=dynamic_cast<Base *>(& a); // 成功转换
A* a_ptr=dynamic_cast<A *>(& b); // nullptr
A* c_ptr=dynamic_cast<A *>(b_ptr); // 成功转换