在Perl中,有一个UNIVERSAL :: can方法可以调用任何类或对象来确定它是否能够执行某些操作:
sub FooBar::foo {}
print "Yup!\n" if FooBar->can('foo'); #prints "Yup!"
Run Code Online (Sandbox Code Playgroud)
假设我在C++中有一个基类指针,它可以是许多不同的派生类中的任何一个,是否有一种简单的方法来完成与此类似的操作?我不想触及其他派生类中的任何内容,我只能更改调用该函数的基类中的区域,以及支持它的派生类.
编辑:等等,现在这是显而易见的(永远不要回答问题),我可以在基数中实现它,返回一个代表UNIMPLEMENTED的数字,然后在调用时检查返回不是这个.我不确定为什么我会以如此复杂的方式思考问题.
我也在想我会从另一个实现的类派生出来foo然后看看这个类的动态转换是否有效.
据我所知,动态强制转换与静态强制转换的不同之处在于它对RTTI的使用,以及如果变量的动态类型 - 从基础转换为派生 - 不适合时,它会失败的事实.但是,如果我们还有RTTI,为什么这个类必须是多态的呢?
编辑:由于对"多态"一词的使用存在一些混淆,这里是cplusplus.com中的条目,促使我这样问:
dynamic_cast只能用于指针和对象的引用.其目的是确保类型转换的结果是所请求类的有效完整对象.
因此,当我们将一个类转换为其基类之一时,dynamic_cast总是成功的
classes: class CBase { };
class CDerived: public CBase { };
CBase b; CBase* pb; CDerived d;
CDerived* pd;
pb = dynamic_cast<CBase*>(&d); //ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b); //wrong: base-to-derived
Run Code Online (Sandbox Code Playgroud)
这段代码中的第二次转换会产生编译错误,因为除非基类是多态的,否则不允许使用dynamic_cast进行基本到派生的转换.
在 OOP 概念中,RTTI(运行时类型信息)是也用于静态转换还是仅用于动态转换?
如果它特定于动态转换,那么请证明您的答案是合理的,并请解释为什么没有用于 static_casting 的 RTTI。
使用 RTTI 进行向下转换有什么意义?
如果我有一个TList,其中有许多不同记录类型的指针,我如何访问TList中的不同记录的值?
有没有办法获取那些引用的recods的记录类型或类型信息?
我目前正在使用Delphi XE.
我想在运行时使用D2010填充通用对象的字段.
program generic_rtti_1;
{$APPTYPE CONSOLE}
uses
SysUtils, rtti;
type
TMyObject = class
FField1: string;
end;
TGeneric<TElement: class> = class
procedure FillFields(Element: TElement);
end;
procedure TGeneric<TElement>.FillFields(Element: TElement);
var
ctx: TRttiContext;
begin
ctx := TRttiContext.Create();
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(@Element, TValue.FromVariant('Some string'));
ctx.Free();
end;
Run Code Online (Sandbox Code Playgroud)
当ctx.Free();执行该行时,我在System.pas(函数_IntfClear())的21986行获得一个AV.这是从FContextToken := nilrtti.pas中调用的.(实际上,SetValue如果我介入SetValue,会弹出诱导的AV ,但如果单步执行,则仅ctx.Free报告-induced.请参阅下文.)
如果我删除ctx.Free();,则在呼叫时出现AV SetValue(@Element, TValue.FromVariant('Some string'));.这也是在System.pas中的21986行.
试图弄清楚这个烂摊子,我换了
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(@Element, TValue.FromVariant('Field 1 is set'));
Run Code Online (Sandbox Code Playgroud)
有了这个:
rType := ctx.GetType(TypeInfo(TElement));
rField := rType.GetField('FField1');
Val := TValue.FromVariant('Field 1 is set'); …Run Code Online (Sandbox Code Playgroud) 我正在尝试procedure of object使用TRttiProperty.SetValue过程通过rtti 分配一个类型的属性,但是当我尝试进行赋值时会引发此异常EInvalidCast: Invalid class typecast
此示例应用程序显示了该问题
{$APPTYPE CONSOLE}
uses
Rtti,
SysUtils;
type
TMyCallBack = procedure (const Foo : string) of object;
TMyClass = class
procedure DoSomething(const Foo: String);
end;
TMyAnotherClass = class
private
FDoSomething: TMyCallBack;
published
property DoSomething : TMyCallBack read FDoSomething Write FDoSomething;
end;
{ TMyClass }
procedure TMyClass.DoSomething(const Foo: String);
begin
Writeln('Hello');
end;
Var
MyClass : TMyClass;
t : TRttiInstanceType;
v : TValue;
p : TRttiProperty;
Bar : TMyCallBack;
begin
try …Run Code Online (Sandbox Code Playgroud) 我有一个这样的 TForm:
TMyForm = class (TForm)
[MyAttr('Data')]
edit1: TEdit;
private
FData: String;
end
Run Code Online (Sandbox Code Playgroud)
当我尝试通过 RTTI 获取此表单的字段时,我只获取了 edit1 字段,而不是 FDATA,并且当我查询 edit1 字段属性时,会得到一个空数组。
对于另一个不继承 TForm 的类,一切正常。为什么?
编辑样品
type
{$RTTI EXPLICIT FIELDS([vcPrivate,vcProtected, vcPublic])}
TForm3 = class(TForm)
[TCustomAttribute]
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
[TCustomAttribute]
FData: String;
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject);
var
LCtx: TRttiContext;
LField: TRttiField;
LAttr: TCustomAttribute;
begin
for LField in LCtx.GetType(Self.ClassInfo).GetDeclaredFields do
begin
Memo1.Lines.Add(lField.Name);
for …Run Code Online (Sandbox Code Playgroud) 我发现TVirtualMethodInterceptor.Create不支持具有重载虚方法的类.举些例子
type
TLog = class
public
constructor Create();
procedure SaveLog(str: string); overload; virtual;
procedure SaveLog(str: string; Args: array of const); overload; virtual;
end;
constructor TLog.Create(str: string);
begin
end;
procedure TLog.SaveLog(str: string);
begin
end;
procedure TLog.SaveLog(str: string; Args: array of const);
begin
end;
procedure MyTest();
var
ttt: TLog;
vmi: TVirtualMethodInterceptor;
begin
ttt:=TLog.Create();
try
vmi:=TVirtualMethodInterceptor.Create(ttt.ClassType);
try
//
finally
vmi.Free();
end;
finally
ttt.Free();
end;
end;
Run Code Online (Sandbox Code Playgroud)
执行TVirtualMethodInterceptor.Create()时,它将引发异常"可用于支持此操作的RTTI不足".有人可以帮帮我吗?
试图在运行时将对象转换为JSON,我得到的RTTI错误不足.对象是:
{$M+}
{$TYPEINFO ON}
{$METHODINFO ON}
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished]) PROPERTIES([vcPublic, vcPublished])}
TMyPacket = class(TObject)
Private
FID: TGUID;
FToIP: string;
FToPort: integer;
FSent: boolean;
FSentAt: TDateTime;
FAck: boolean;
FTimeOut: Cardinal;
FDataToSendSize: UINT64;
FDataToSend: AnsiString;
public
constructor create;
destructor free;
published
property ID: TGUID read FID write FID;
property ToIP: string read FToIP write FToIP;
property ToPort: integer read FToPort write FToPort;
property Sent: boolean read FSent write FSent;
property SentAt: TDateTime read FSentAt write FSentAt;
property Ack: boolean read FAck …Run Code Online (Sandbox Code Playgroud) 我在Delphi中使用windows dll,我必须检查我的功能是否分配得很好.
我声明了函数类型,以便将我的dll函数放在类属性中,如下所示:
type
MPOS_OpenResource = function (ResID: DWORD; CplNum:BYTE; BlockingMode: DWORD):WORD;stdcall;
MPOS_CloseResource = function (ResID: DWORD; CplNum:BYTE):WORD;stdcall;
MPOS_GetResourceID = function (CplNum : Byte; ResID : PDWord) : word;stdcall;
...
Run Code Online (Sandbox Code Playgroud)
然后,我为我的dll类中的每个相应字段分配一个方法,如下所示:
@Self.m_MPOS_OpenResource := GetProcAddress( libHandler, '_MPOS_OpenResource@12' );
@Self.m_MPOS_CloseResource := GetProcAddress( libHandler, '_MPOS_CloseResource@8' );
@Self.m_MPOS_GetResourceID := GetProcAddress( libHandler, '_MPOS_GetResourceID@8');
...
Run Code Online (Sandbox Code Playgroud)
我最后检查每个分配是否使用了一个巨大的if条款:
If(not Assigned(@m_MPOS_OpenResource) OR
not Assigned(@m_MPOS_CloseResource) OR
not Assigned(@m_MPOS_GetResourceID) OR
...) then { Some code for exception}
Run Code Online (Sandbox Code Playgroud)
我想避免if使用反射的giantic 子句,但我找不到有用的东西.我尝试了很多东西,最后一个开始:
for f in rttiType.GetFields() do
if(not Assigned(rttiType.GetField(f.Name).GetValue(Self))
OR …Run Code Online (Sandbox Code Playgroud) rtti ×10
delphi ×7
c++ ×3
casting ×2
delphi-2010 ×1
delphi-xe ×1
delphi-xe2 ×1
delphi-xe3 ×1
dll ×1
generics ×1
oop ×1
pascal ×1
pointers ×1
record ×1
runtime ×1