C++ 在C+中销毁基类时,是否可能知道派生实例类型+;?

C++ 在C+中销毁基类时,是否可能知道派生实例类型+;?,c++,inheritance,destructor,C++,Inheritance,Destructor,假设我有纯类A和类B,C,D,等等,都是从A派生出来的。可以从A的析构函数中知道正在销毁哪个派生类吗?可以在使用时执行,如下所示: template <typename TDerived> class Base {}; class Derived : public Base<Derived> {}; 模板 类基{}; 派生类:公共基{}; 然后Base随时知道派生类型。这取决于您需要什么。当然,这里有人会问为什么,这是一个值得怀疑的愿望 在编译时,不可能随时从基类自

假设我有纯类
A
和类
B
C
D
,等等,都是从
A
派生出来的。可以从
A的析构函数中知道正在销毁哪个派生类吗?

可以在使用时执行,如下所示:

template <typename TDerived>
class Base {};

class Derived : public Base<Derived> {};
模板
类基{};
派生类:公共基{};

然后
Base
随时知道派生类型。

这取决于您需要什么。当然,这里有人会问为什么,这是一个值得怀疑的愿望

在编译时,不可能随时从基类自动了解对象的动态类型。如果您想在编译时知道该类型,唯一的解决方案是将该信息包含在基类类型本身中,这基本上就是CRTP模式。例如:

class BaseBase {
    // body
};

template <typename D>
class Base : BaseBase {
    //body
};

class Derived1 : public Base<Derived1> {
    // body
};

class Derived2 : public Base<Derived2> {
    // body
};

请注意,这取决于
Base
构造函数将在
派生的
构造函数之前运行,因此
类型
指针将引用当前已构造的最派生的类。

CRTP的问题是,您有不同的基类型,不能用于动态多态性

如果您不需要派生对象的实际类型,但希望根据它执行代码,则有不同的可能性。请注意,您不能调用析构函数中的任何虚拟函数。但是,您可以:

一,。添加一个类型成员变量(可以是
std::type_info
、一个枚举或其他任何变量)并对其手动分派

二,。使用技术作为的对应项,在显式销毁之前调用函数(通过
delete
或类似方式)。但是,这可能会被遗忘,或者(如果强制)严重限制了销毁对象的方式

三,。您可以使用策略模式:

class Base
{
    struct Strategy
    { 
        virtual ~Strategy();
        virtual void onDestroy() = 0;
    }

    std::unique_ptr<Strategy> strategy;

public:
    explicit Base(std::unique_ptr<Strategy> strategy)
    : strategy(std::move(strategy))
    {
    }

    virtual ~Base()
    {
        strategy->onDestroy();
    }
};

class Derived1 : public Base
{
    struct Strategy1 : Strategy
    {
        virtual void onDestroy() { ... }
    };

public:
    Derived1()
    : Base(std::make_unique<Strategy1>())
    {
    }
};
类基
{
结构策略
{ 
虚拟策略();
虚拟空onDestroy()=0;
}
std:独特的ptr策略;
公众:
显式基础(标准::唯一的ptr策略)
:策略(标准::移动(策略))
{
}
虚拟~Base()
{
策略->onDestroy();
}
};
类Derived1:公共基
{
结构策略1:策略
{
虚拟空onDestroy(){…}
};
公众:
Derived1()
:Base(std::make_unique())
{
}
};
请注意,对于C++11函数对象,这变得相当简单:

class Base
{
    std::function<void()> strategy;

public:
    explicit Base(std::function<void()> strategy)
    : strategy(std::move(strategy))
    {
    }

    virtual ~Base()
    {
        strategy();
    }
};

class Derived1 : public Base
{
public:
    Derived1()
    : Base([] () { ... })
    {
    }
};
类基
{
功能策略;
公众:
显式基(std::函数策略)
:策略(标准::移动(策略))
{
}
虚拟~Base()
{
策略();
}
};
类Derived1:公共基
{
公众:
Derived1()
:Base([](){…})
{
}
};

重要提示:您必须确保策略对象或函数对象不引用派生类的任何成员,因为派生对象在调用时已被销毁。如果您需要访问成员属性,最好直接重新定义析构函数。

我猜您的意思是自动,也就是说,编译器会告诉您?“手动”解决方案是添加一些存储最派生类型的数据成员,例如
type\u info const&
.No。至此,所有衍生零件都消失了。为什么需要这个?我想知道,如果将基本析构函数标记为virtual并在每个派生函数中重写析构函数,是否可以达到相同的目的classes@Jimmy:析构函数在这方面很特别,因为重写B::~B仍将调用A::~A。回到A::~A中,您不知道自己来自何处。您忘记了在第二个示例中继承
Base
class Base
{
    std::function<void()> strategy;

public:
    explicit Base(std::function<void()> strategy)
    : strategy(std::move(strategy))
    {
    }

    virtual ~Base()
    {
        strategy();
    }
};

class Derived1 : public Base
{
public:
    Derived1()
    : Base([] () { ... })
    {
    }
};