Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Setting Base class properties using RTTI not working?


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 16 - Last Post: May 20, 2016 10:35 AM Last Post By: Remy Lebeau (Te...
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Setting Base class properties using RTTI not working?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 14, 2016 5:49 AM
Hi,

I was wondering if this is a bug or i am making something wrong here because
i am trying to set a property that was actually declared in the base class but for
some reason it does not set the value as i want it. But if the property is declared
inside the current subclass it works fine.

Here is the code:

//Base Class
 
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <System.SysUtils.hpp>
//---------------------------------------------------------------------------
#pragma explicit_rtti methods (__published, public) properties (__published, public) 
fields(__published, public, protected, private)
class DECLSPEC_DRTTI TMyBaseComponent : public TComponent
{
	typedef TComponent inherited;
 
private:
//Fields
UnicodeString FTitle;
UnicodeString FDetail;
 
protected:
//Setters/Getters
virtual void __fastcall SetTitle(UnicodeString Value);
virtual void __fastcall SetDetail(UnicodeString Value);
 
public:
//Constructor / Destructor.
__fastcall TMyBaseComponent (TComponent* Owner);
virtual __fastcall ~TMyBaseComponent (void);
 
//Fields/Properties
__property UnicodeString Title = {read = FTitle, write = SetTitle};
__property UnicodeString Detail = {read = FDetail, write = SetDetail};
};
 
//---------------------------------------------------------------------------
 
 
//Derived Class
 
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <System.SysUtils.hpp>
#include "MyComponent.h"
//---------------------------------------------------------------------------
#pragma explicit_rtti methods (__published, public) properties (__published, public) 
fields(__published, public, protected, private)
class DECLSPEC_DRTTI TMyDerivedComponent : public TMyBaseComponent 
{
	typedef TMyBaseComponent inherited;
 
private:
//Fields
UnicodeString FURL;
 
public:
 
//Fields/Properties
__property UnicodeString URL = {read = FURL, write = FURL};
 
//Constructor / Destructor.
__fastcall TMyDerivedComponent(TComponent* Owner);
virtual __fastcall ~TMyDerivedComponent(void);
};
//---------------------------------------------------------------------------
 
 
//SetPropertyValue
 
//---------------------------------------------------------------------------
void SetPropertyValue(TObject* Instance, UnicodeString PropertyName, TValue Value)
{
TRttiContext AContext = CreateContext();
 
//if i changed this to Instance->ClassParent() works fine with setting base class properties.
TRttiType* RttiType = AContext.GetType(Instance->ClassInfo());   
if (RttiType)
	{
 
	try
		{
		TRttiProperty* Prop = GetProperty(RttiType,PropertyName);
 
		if (Prop)
			{
 
			try
				{
				if (Prop->IsWritable)
					{
					Prop->SetValue(Instance, Value);
					}
				}
			__finally
				{
				Prop->Free();
				}
			}
		}
	__finally
		{
		RttiType->Free();
		AContext.Free();
		}
	}
}
//---------------------------------------------------------------------------
 
//Using Code
 
void __fascall TForm1::Button1Click(TObject *Sender)
{
TMyBaseComponent* AComponen= (TMyBaseComponent*)CreateComponent(__classid(TMyBaseComponent), AOwner);
 
UnicodeString s = "hello world";
	
SetPropertyValue(AComponen,"Title", TValue::_op_Implicit(s));         // raises an exception full of ??????
}

Any help will be appreciated
--
The limits of my language mean the limits of my world

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 14, 2016 8:13 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Prop->Free();
RttiType->Free();

DO NOT call those! Those objects are owned by the TRttiContext and will
be released automatically. You are not responsible for freeing them.

TMyBaseComponent* AComponen=
(TMyBaseComponent*)CreateComponent(__classid(TMyBaseComponent),
AOwner);

You are creating an instance of the base class, not the derived class, so
SetPropertyValue() cannot access any properties from the derived class.

SetPropertyValue(AComponen,"Title", TValue::_op_Implicit(s));

You should use TValue::From() instead of calling _op_Implicit() directly:

SetPropertyValue(AComponen, "Title", TValue::From(s));
or
SetPropertyValue(AComponen, "Title", TValue::From<UnicodeString>(s));


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 15, 2016 1:06 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
No sorry that came out wrong it be like this:

void __fascall TForm1::Button1Click(TObject *Sender)
{
//Corrected
TMyBaseComponent* AComponen= (TMyBaseComponent*)CreateComponent(__classid(TMyDerivedComponent), AOwner);
 
UnicodeString s = "hello world";
	
SetPropertyValue(AComponen,"Title", TValue::_op_Implicit(s));         // raises an exception full of ??????
}


The reason why i use "_op_Implicit" instead of "From" is that every time
i use From the program crashes at startup and raises that error in that function:

class function TMonitor.GetFieldAddress(const AObject: TObject): PPMonitor;
begin
  Result := PPMonitor(PByte(AObject) + AObject.InstanceSize - hfFieldSize + hfMonitorOffset);
end;
 
//First chance exception at $004226C4. Exception class $C0000005 with message 
'access violation at 0x004226c4: read of address 0x00000000'. Process PushNotification.exe (2384)


_op_Implicit works fine actually and it sets derived class properties fine the problem
with base class propertie, i even tried using "SetStrProp" from "System.TypInfo.hpp"
but it always gave me error that it cant't find a property with that name "Title".

--
The limits of my language mean the limits of my world
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 15, 2016 7:29 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
It worked for setting base class property when i removed these:

Prop->Free();
RttiType->Free();


But now I am facing another problem with invoking methods from the base class,
for instance if there is a method in the base class like this:

virtual void __fastcall DoSomething();
//without overriding it in derived class
//I invoke it like this:
 
TRttiContext AContext = CreateContext();
TRttiType* RttiType = AContext.GetType(AComponen->ClassType());
 
if (RttiType)
	{
	try
		{
		TRttiMethod* Method = GetMethod(RttiType,"DoSomething");
 
		if (Method)
			{
			Method->Invoke(Notification, NULL,-1);         //Nothing happens
			}
		}
	__finally
		{
		AContext.Free();
		}
	}
 
//But when i remove this line from base class unit:
 
#pragma explicit_rtti methods (__published, public) properties (__published, public) 
fields(__published, public, protected, private)
 
The method gets invoked successfully without any problems but setting base class 
properties do not work again.


What are the correct RTTI directives for my case?

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 16, 2016 10:35 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Method->Invoke(Notification, NULL,-1); //Nothing happens

What is Notification? The first parameter of TRttiMethod::Invoke() is the
object instance or class type to call the method on, ie the method's 'this'
pointer. You should be passing in the same AComponen object that you used
to get the TRttiMethod from.

AContext.Free();

You don't actually need to call Free(), TRttiContext is a record on the stack
and will be cleaned up automatically when it goes out of scope. So you can
get rid of your try/finally altogether.

What are the correct RTTI directives for my case?

Why are you doing all of this work using RTTI in the first place, instead
of using normal polymorphism? What are you really trying to accomplish?

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 16, 2016 10:49 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Sorry that should have been AComponent. My mistake I copying the code
from a source i have but i'm changing it here for simplicity:

Method->Invoke(AComponent, NULL,-1);


Now, What i am trying to do is creating a component instances derived from
a base class and setting its properties and calling a method based on a data
sent from another application using TIdUDPServer OnRead event.

That's why i am using RTTI. The problem i am having now is that i can't
understand how RTTI works regarding my case.

Let's recap at first setting properties weren't working because of the existence
of these lines in my code:

Prop->Free();
RttiType->Free();


When i removed them setting properties of my base and derived class worked fine.

Now the new problem is invoking base class methods. Is there a global directive
that i can use like "DECLSPEC_DRTTI" before creating class to this more easier?

Now why base class method does not get invoked with code like this:

void InvokeMethod(TObject* Instance, UnicodeString MethodName)
{
TRttiContext AContext = CreateContext();
TRttiType* RttiType = AContext.GetType(Instance->ClassParent());
 
if (RttiType)
	{
	try
		{
		TRttiMethod* Method = GetMethod(RttiType,MethodName);
 
		if (Method)
			{
			Method->Invoke(Instance,NULL,-1);
			}
		}
	__finally
		{
		AContext.Free();
		}
	}
}
//---------------------------------------------------------------------------


While setting properties of base class works fine with this code:

void SetPropertyValue(TObject* Instance, UnicodeString PropertyName, TValue Value)
{
TRttiContext AContext = CreateContext();
 
TRttiType* RttiType = AContext.GetType(Instance->ClassInfo());
 
if (RttiType)
	{
	try
		{
		TRttiProperty* Prop = GetProperty(RttiType,PropertyName);
 
		if (Prop)
			{
			if (Prop->IsWritable)
				{
				Prop->SetValue(Instance, Value);
				}
			}
		}
	__finally
		{
		AContext.Free();
		}
	}
}
//---------------------------------------------------------------------------


I really need this to work.
--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 17, 2016 10:01 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Now the new problem is invoking base class methods.

And what exactly happens when you try to invoke it? Does GetMethod() return
a valid TRttiMethod pointer? When Invoke() is called, does the code crash,
or does the code simply nott do anything? Have you tried enabling Debug
DCUs in the Project Options and then step into Invoke() with the debugger
to find out what it really does? Please be more specific.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 17, 2016 12:54 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
After enabling use debug DCUs the IDE showed me this exception:

procedure CheckCodeAddress(code: Pointer);
begin
  if (code = nil) or (PPointer(code)^ = nil) then //Exception is here
    raise InsufficientRtti;
end;
 
//First chance exception at $0047321C. Exception class $C0000005 
with message 'access violation at 0x0047321c: read of address 0x40b7c800'. 
Process PushNotification.exe (5624)


So, what does that mean?
--
The limits of my language mean the limits of my world
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 12:31 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello, Remy Do you know what is wrong with it? is it a bug or c++ builder does not support invoking methods of classes created by C++ builder?

--
The limits of my language mean the limits of my world
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 12:54 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I managed to make it work but i had to remove virtual from method declaration like in Datasnap methods:

virtual void __fastcall DoSomething();
 
//After making the function look like this:
void DoSomething();


But how am i going to inherit this function in derived classes without using virtual
--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 10:02 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

But how am i going to inherit this function in derived classes without
using virtual

You can't. But what you can do is add another virtual method that DoSomething()
then calls, eg:

virtual void __fastcall ActuallyDoSomething();
void DoSomething() { ActuallyDoSomething(); }


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 12:34 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:

You can't. But what you can do is add another virtual method that DoSomething()
then calls, eg:

virtual void __fastcall ActuallyDoSomething();
void DoSomething() { ActuallyDoSomething(); }

Why? i can do something like this and it worked:

class Base : public TObject
{
protected:
UnicodeString Text;
public:
__fastcall Base(const UnicodeString AText)
: Text(AText)
{
 
}
 
void __fastcall ShowText()
{
ShowMessage(Text);
}
 
};
//--------------
class Derived : public Base
{
public:
__fastcall Derived(UnicodeString AText)
: Base(AText)
{
}
 
void __fastcall ShowText()
{
Text = " World";
Base::ShowText();
}
};


Or do you mean that it won't work with RTTI method invoking?

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 1:07 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

Why?

Because you said a virtual method doesn't get invoked correctly via RTTI
but a non-virtual method does. So use RTTI to invoke a non-virtual method
that then internally calls a virtual method.

i can do something like this and it worked:

That code is not using polymorphism for ShowText(). The Derived::ShowText()
method is hiding the Base::ShowText() method instead of overriding it. As
such, you can't call Derived::ShowText() from a Base* pointer since Base::ShowText()
is not virtual.

Or do you mean that it won't work with RTTI method invoking?

That is what yousaid, not me.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 1:34 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
How come that this code is just hiding base class methods
Whether the function is virtual or not I always do this:


//Base function
virtual void __fastcall ShowText()
{
ShowMessage(Text);
}
 
//Derived function
virtual void __fastcall ShowText()
{
Text = " World";
 
//Whether the base class function is virtual or 
//not we always add the inherited from base in 
//derived class overridden function.
Base::ShowText();       
}
 
//When i call these methods even with RTTI it works fine:
 
Base *B = new Base("Hello");
 
B->ShowText();     //Here shows a message box with "Hello"
 
Derived *D = new Derived("Hello");
 
InvokeMethod(D,"ShowText");     //Here shows a message box with " World"
 


Or is there another way to override functions that i don't know about?

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 19, 2016 2:09 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

How come that this code is just hiding base class methods Whether
the function is virtual or not

If a base method is NOT virtual, declaring a method of the same name in a
derived class does not override the base method, and so the derived method
cannot be called from a Base pointer like a virtual method can.

If the signature of the derived method does not match the signature of the
base method, the derived method hides the base method, and you get a compiler
warning.

I always do this:

That code is using a virtual method.

//When i call these methods even with RTTI it works fine:

That is not what you said earlier. You said RTTI was having trouble invoking
a virtual method. Now you say it works. You are contradicting yourself.
What is the REAL problem you are having?

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: Setting Base class properties using RTTI not working? [Edit] [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 20, 2016 1:22 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I know what you mean, and i am sorry i put virtual in that code
just to demonstrate my point that i always use the base class
method inside the derived one:

#pragma explicit_rtti methods (__published, public) properties 
(__published, public) fields(__published, public, protected, private)
class DECLSPEC_DRTTI Base : public TObject
{
protected:
UnicodeString Text;
public:
__fastcall Base(const UnicodeString AText)
: Text(AText)
{
 
}
 
void __fastcall ShowText()
{
ShowMessage(Text);
}
 
};
//--------------
#pragma explicit_rtti methods (__published, public) properties 
(__published, public) fields(__published, public, protected, private)
class DECLSPEC_DRTTI Derived : public Base
{
public:
__fastcall Derived(UnicodeString AText)
: Base(AText)
{
}
 
void __fastcall ShowText()
{
Text = " World";
Base::ShowText();
}
};
//Calling it
 
Base *D = new Derived("Hello");
 
D->ShowText();    //here it will still call base method not the derived.
 


And yes virtual methods don't work with RTTI I have no idea why that
is happening while all C++ generated headers from Delphi code have
there functions as virtual and they all work fine with RTTI even in C++ programs.
Its weird and I can't find a work-around for this by using virtual functions with RTTI.

It is very annoying really Embarcadero must work a lot more on fixing RTTI
problems in C++ builder.

if there is no go with delphi RTTI. Is there any other way to do so like using
boost, STL, etc? I mean to just invoke virtual function just using its name?

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Setting Base class properties using RTTI not working? [Edit] [Edit][Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 20, 2016 10:35 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed wrote:

And yes virtual methods don't work with RTTI I have no idea why that
is happening

Then you should file a bug report with Quality Portal.

while all C++ generated headers from Delphi code have there functions
as virtual and they all work fine with RTTI even in C++ programs.

Because those classes are implemented in Dephi and have been marked with
DELPHICLASS and PASCALIMPLEMENTATION in C++:

http://docwiki.embarcadero.com/RADStudio/en/Declspec(delphiclass)
http://docwiki.embarcadero.com/RADStudio/en/Declspec(pascalimplementation)

if there is no go with delphi RTTI. Is there any other way to do
so like using boost, STL, etc? I mean to just invoke virtual function
just using its name?

Without viable RTTI, you would have to manually setup your own lookup table
of names to function pointers, such as with a std::map.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02