在C++中,有没有办法查询对象的类型,然后使用该信息动态创建相同类型的新对象?
例如,假设我有一个简单的3类层次结构:
class Base
class Foo : public Base
class Bar : public Base
Run Code Online (Sandbox Code Playgroud)
现在假设我给你一个类型为Base的对象 - 实际上是Foo类型.有没有办法查询类型并使用该信息以后来创建Foo类型的新对象?
鉴于记录:
MyRecord = record
Company: string;
Address: string;
NumberOfEmplyees: integer;
Run Code Online (Sandbox Code Playgroud)
你能写一个函数调用吗?
function UpdateField(var FieldName: string; FieldValue: variant): bool;
Run Code Online (Sandbox Code Playgroud)
以便:
UpdateField('Company', 'ABC Co');
Run Code Online (Sandbox Code Playgroud)
将MyRecord.Company更新为'ABC Co'?
我找了一个例子,但我发现的一切都是为了数据库.任何指导我正确方向的帮助表示赞赏.
谢谢,查尔斯
在C++中,当我们使用typeid获取对象或类的类型名称时,它将显示一个装饰(受损)字符串.我用cxxabi它去解码它:
#include <cxxabi.h>
#include <typeinfo>
namespace MyNamespace {
class MyBaseClass
{
public:
const std::string name()
{
int status;
char *realname = abi::__cxa_demangle(typeid (*this).name(),0,0, &status);
std::string n = realname;
free(realname);
return n;
}
};
}
int main()
{
MyNamespace::MyBaseClass h;
std::cout << h.name() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出gcc是:
myNameSpace对象:: MyBaseClass
我需要MyNamespace::从上面的字符串中删除.我可以通过字符串操作删除它们 .
但是,有没有标准方法与cxxabi其他库或这样做或明确的解决方案?(至少可以在gcc和Visual C++之间移植)
我已经声明了以下枚举类型,其中我希望第一个成员的序数值为1(一)而不是通常的0(零):
type
TMyEnum = (
meFirstValue = 1,
meSecondValue,
meThirdValue
);
Run Code Online (Sandbox Code Playgroud)
如果我调用TypeInfo(),例如作为对GetEnumName()的调用的一部分,我得到一个编译器错误:
GetEnumName(TypeInfo(TMyEnum), Ord(aValue));
Run Code Online (Sandbox Code Playgroud)
错误:"E2134:类型'TMyEnum'没有typeinfo"
为什么是这样?
我知道,类只有所属类别,如果它们与编译$ M启用编译器选项,或者(在某些类是,如获得TPersistent,但我不认为有具有所属类别的枚举类型的任何特殊情况).
有什么(如果有的话)c ++构造用于在运行时列出类的祖先?
基本上,我有一个类,它存储一个指向任何对象的指针,包括可能是一个原始类型(有点像boost::any,我不想使用它,因为我需要保留我的对象的所有权).在内部,这个指针是一个void*,但是这个类的目标是void*用运行时类型安全包装.赋值运算符是模板化的,因此在赋值时我取出typeid()传入指针并存储它.然后,当我稍后退回时,我可以检查typeid()存储的类型type_info.如果它不匹配,则演员将抛出异常.
但是有一个问题:我似乎失去了多态性.让我们说B是一个基础D.如果我将一个指针存储D在我的类中,那么存储的type_info也将是D.然后,我可能想要检索一个B指针.如果我使用我的类的方法来强制转换B*,那么typeid(B) == typeid(D)失败,并且D->B转换会引发异常,即使转换是安全的.Dynamic_cast<>()这里不适用,因为我是在一个void*而不是一个B或多个祖先的运作D.
我希望能做的就是检查is_ancestor(typeid(B), typeid(D)).这可能吗?(这不是dynamic_cast<>在幕后做的吗?)
如果没有,那么我正在考虑采取第二种方法:实现一个类TypeInfo,其派生类是模板化的单例.然后,我可以在这些类中存储我喜欢的任何信息,然后在我的AnyPointer班级中保留指向它们的指针.这将允许我以更易于访问的方式在编译时生成/存储祖先信息.因此失败的选项#1(列出祖先的内置方式仅给出运行时可用的信息),是否有一个我可以使用的构造/过程,它将允许在编译时自动生成和存储祖先信息,最好没有不必明确输入的是"类A派生自B和C; C从导出D等."?一旦我有这个,有没有一种安全的方式来实际执行该演员表?
使用Delphi 2010中的RTTI系统,有没有办法找出属性是否是TDateTime?每当我回调asVariant并且如果我检查属性类型时,它当前将它视为双精度.这是因为它只能看到基本类型吗?(TDateTime = double)
问题与此问题有些类似,但接受的答案并未真正提出解决方案或解决方法.
在我们的项目中,我们有一个dylib和主要的可执行文件.dylib使用-fno-rtti,而可执行文件使用RTTI 编译.当std::bad_alloc从dylib抛出异常(例如)并在exe中捕获时,会发生此问题.
(在你大喊"异常需要RTTI所以你必须有它!",请注意,必要的例外RTTI总是产生不管的-frtti或-fno-rtti设置.这实际上是在记录-fno-rtti标志的说明.在OS X上的问题是,它不是以相同的方式生成的)
经过一番调查,发现了以下内容:
-fno-rtti)中,有一个异常的RTTI结构的本地副本; 特别是__ZTISt9bad_alloc符号(typeinfo for std::bad_alloc).-frtti)从中导入typeinfo符号libstdc++.6.dylib,但没有本地副本由于异常处理代码依赖于比较typeinfo指针来确定异常匹配,因此匹配失败,只有catch(...)成功.
到目前为止,我看到以下选项:
1)编译所有内容,或者至少编译抛出和捕获异常的文件-frtti.这是可行的,但我不喜欢为所有东西生成RTTI的想法,即使我们不使用它; 并且使用异常的文件列表很容易变得陈旧.
2)当链接dylib时,以某种方式使链接器从目标文件中丢弃弱异常定义并使用它来自libstdc++.6.dylib.到目前为止,我没有成功.
3)???
我做了一个小测试来说明这个问题.
--- throw.cpp ---
#include <iostream>
#if defined(__GNUC__)
#define EXPORT __attribute__((visibility("default")))
#else
#define EXPORT __declspec(dllexport)
#endif
EXPORT void dothrow ()
{
std::cout << "before throw" << std::endl;
throw std::bad_alloc();
}
--- main.cpp --- …Run Code Online (Sandbox Code Playgroud) 可以使用禁用的运行时类型信息编译C++代码,这会禁用dynamic_cast.但是,仍然需要根据目标的运行时类型调度虚拟(多态)方法.这是否意味着类型信息无论如何dynamic_cast都应该存在,并且应该能够始终工作?
在C++程序中启用RTTI的内存/性能开销是多少?
任何人都可以在RTTI机制的内部实现和相关的开销之间提出一些建议吗?
我明白如何通过使用RTTI typeid和dynamic_cast,我试图了解的是运行时间如何跟踪这些信息的内部实现细节,它是如何开销?
rtti ×10
c++ ×6
delphi ×4
attributes ×1
casting ×1
delphi-2010 ×1
delphi-7 ×1
enums ×1
exception ×1
inheritance ×1
macos ×1
polymorphism ×1
tdatetime ×1
typeid ×1
typeinfo ×1