Cad*_*hon 5 c++ inheritance typeid
我刚刚发现了以下行为:具有B从类型派生的类型的对象,A构造期间的最终类型A是A和否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)
我知道我可以在子节点的每个构造函数/析构函数中执行通知,但它不太健壮(如果资源在没有通知管理器的情况下实例化,则可能出现错误). 你有什么想法解决方法吗?
听起来你正在寻找的是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)
| 归档时间: |
|
| 查看次数: |
109 次 |
| 最近记录: |