在构造过程中更改的对象类型
Type of an object changing during construction
我刚刚发现了以下行为:有一个从类型A
派生的B
类型的对象,构造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;
}
这段代码(用gcc 4.8.5编译(如下:
0x400ae0
0x400ae0
0x400ac0
我们可以看到 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
};
我知道我可以在子级的每个构造函数/析构函数中进行通知,但它不太健壮(如果在没有通知管理器的情况下实例化资源,则可能会出现错误(。您对解决方法有任何想法吗?
听起来你要找的是CRTP
template<typename Concrete>
struct Resource
{
Resource() { ResourceManager::notifyCreation(*static_cast<Concrete*>(this)); }
~Resource() { ResourceManager::notifyDestruction(*static_cast<Concrete*>(this)); }
};
struct MyResource : Resource<MyResource>
{
};
请注意,在调用notifyCreation
时,MyResource
尚未完成构造。可以获取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
}
};
没有像您的示例那样在构造函数中做到这一点的好方法,但是您可以为A
提供一个特殊的构造函数,即
A(const std::type_info &info) {
std::cout << info.name() << std::endl;
}
并在B
B() : A(typeid(*this)) {
std::cout << typeid(*this).name() std::endl;
}
如果在构造函数之外执行此操作,还可以在"A"中提供一个虚拟函数,并在"B"中覆盖它。
相关文章:
- 在 C++ 中将一个模板类型的对象类型转换为另一个模板类型
- 了解 Python 中的对象类型
- 具有纯虚函数和指针数组对象类型的父类的指针数组
- 调用的对象类型 'double' 不是 report() 函数的函数或函数指针
- 基准、值、值类型、对象和对象类型(C++)
- JNI 如何将 Java 对象数组传递给相同对象类型的 C++ 数组
- 在构造过程中更改的对象类型
- 如何构建程序以避免查询对象类型?
- 如何使用Dynamic_cast获得对象类型
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- static_cast实际上不是对象类型的类型是未定义的行为吗?
- 为什么 std::variant 不能容纳数组对象类型,而联合可以?
- 为什么类型转换对象不会更改其地址?有关对象类型的信息存储在哪里?
- 类返回对象类型,但如何返回和检查 null
- 是否可以在辅助功能中概括对象类型
- 表达式必须在C 中具有指针对象类型
- 下标需要数组或指针类型表达式必须具有指针对象类型
- 当将对象传递给具有参数作为引用类型的函数以及当其类对象类型时,会得到不同的输出
- 如何在运行时指定对象类型
- 我可以获取在重载的新运算符中使用新运算符的对象类型吗?