在施工期间更改的对象类型

Cad*_*hon 5 c++ inheritance typeid

我刚刚发现了以下行为:具有B从类型派生的类型的对象,A构造期间的最终类型AA和否B.这可以通过以下示例观察到:

#include <iostream>
#include <typeinfo>

class A
{
    public:
        A() { std::cout << &typeid(*this) << std::endl; }
};

class B : public A
{
    public:
        B() : A() { std::cout << &typeid(*this) << std::endl; }
};

int main()
{
    A a;
    B b;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

运行此代码(使用gcc 4.8.5编译)如下:

0x400ae0
0x400ae0
0x400ac0
Run Code Online (Sandbox Code Playgroud)

我们可以看到typeid返回的类型A::A()A和不是B,然后最终类型变为B.

为什么?

在构建父类时是否可以知道"真正的"最终类型?

我的背景如下:

我有一个父类Resource和几个继承自它的类.ResourceManager每个资源的创建都会通知我,并且必须知道所创建资源的最终类型.我正在做的是为了避免重复的代码如下,但它不起作用:

class Resource
{
  public:
    Resource() { ResourceManager::notifyCreation(*this); }
    ~Resource() { ResourceManager::notifyDestruction(*this); }
};
class MyResource : public Resource
{
  // I don't have to care to the manager here
};
Run Code Online (Sandbox Code Playgroud)

我知道我可以在子节点的每个构造函数/析构函数中执行通知,但它不太健壮(如果资源在没有通知管理器的情况下实例化,则可能出现错误). 你有什么想法解决方法吗?

Pas*_* By 5

听起来你正在寻找的是CRTP

template<typename Concrete>
struct Resource
{
    Resource() { ResourceManager::notifyCreation(*static_cast<Concrete*>(this)); }
    ~Resource() { ResourceManager::notifyDestruction(*static_cast<Concrete*>(this)); }
};

struct MyResource : Resource<MyResource>
{

};
Run Code Online (Sandbox Code Playgroud)

请注意,MyResource在进行调用时尚未完成构造notifyCreation.MyResource可以采用实例的地址,但这是关于可以对实例执行的所有操作.(感谢Caleth指出这一点)

尤其来自[class.cdtor]

如果操作数typeid引用正在构造或销毁的对象,并且操作数的静态类型既不是构造函数或析构函数的类,也不是其基础之一,则行为是未定义的.

因此ResourceManager,必须在某种程度上实现这样才能使用typeid

struct ResourceManager
{
    template<typename T>
    void notifyCreation(T&&)
    {
        add(typeid(T));  // can't apply to an expression
    }
    template<typename T>
    void notifyDestruction(T&&)
    {
        remove(typeid(T));  // can't apply to an expression
    }
};
Run Code Online (Sandbox Code Playgroud)