By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,825 Members | 1,026 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,825 IT Pros & Developers. It's quick & easy.

Get Derived (templated) from Base Pointer?

P: 1
I have a templated class, CDerived:

template <typename TValue, typename TDraw, typename TEdit ...>
class CDerived : public CBase
{
TValue m_Value
public:

TValue& GetValue() const
{
return m_Value;
}

void Draw()
{
TDraw::Draw(this);
}

void Edit()
{
TEdit::Edit(this);
}
};

It is designed as a generic class that is constructed by passing in various "policy classes" as template arguments (different composite types are created using typedefs). I need to store pointers to CDerived objects in a container.

In order to accomplish this, I've created a non-templated CBase from which CDerived derives, in order to store the CBase* pointers in the container, since the container cannot store CDerived* pointers since they are not all of the same type due to the template arguments of CDerived.

I have a few pure virtual functions in CBase that are overriden in CDerived. In it's implementation, CDervied just makes calls to the policy classes static methods, passing in it's this pointer. This works fine as long as the virtual functions in CBase and CDerived have the same signatures (parameter types and return type).

My problem occurs in that one of the template members passed into CDerived is a Value that it holds. Value can be any arbitrary object, not necessarily a POD type. The only rule is that the TDraw, TEdit, etc. must be able to handle the TValue type.

I need to be able to call GetValue() in the container, but since the container only holds CBase* objects, it can't call GetValue(). GetValue() cannot be a virtual function because the return type is variable depending on the TValue template argument in CDerived. It cannot be a templated virtual function because templated virtual functions are not allowed (MSVC). It cannot be a simple template function because CBase does not know the return type and CBase cannot be templated if stored in a homogenous container.

I've experimented with many different approaches, including handle classes, visitor objects, chameleon objects, etc.; none of which work.

None of these work because in all cases you need to know the target types beforehand, and I don't know all of the target types because CDerived is templated with exponential combinations of template types.

It's interesting that sizeof() and typeid() obviously are able to figure out the type of the derived class from a base class pointer, but there appears to be no support in the language for figuring this out.

What I need to do is either:
1) Given a CBase* pointer, in a container that does not know beforehand what specific CDerived is pointed to, get a CDerived* pointer and be able to call methods on that pointer.
2) Have a way to store CDerived* objects on a container and get the properly-typed pointer out in the container and call methods on it (without the container knowing the pointer's type beforehand, just that the pointed-to object does implement the methods, such as GetValue() that will be called by the container).

I have a feeling that there must be some way to do this, though I have not seen anything that indicates it is possible.

Does anyone have any ideas?

~Mike
Dec 6 '07 #1
Share this Question
Share on Google+
2 Replies


weaknessforcats
Expert Mod 5K+
P: 9,197
Not true:
It cannot be a templated virtual function because templated virtual functions are not allowed (MSVC).
I converted your snippet to templates then compiled and linked it using Visual Studioi.NET 2005:
Expand|Select|Wrap|Line Numbers
  1. template <typename TValue, typename TDraw, typename TEdit >
  2. class CBase
  3. {
  4.     public:
  5.         virtual TValue GetValue() const;
  6. };
  7.  
  8. template <typename TValue, typename TDraw, typename TEdit >
  9. class CDerived : public CBase<TValue,TDraw,TEdit>
  10. {
  11. TValue m_Value;
  12. public:
  13.  
  14. virtual TValue& GetValue() const
  15. {
  16. return m_Value;
  17. }
  18.  
  19. void Draw()
  20. {
  21. TDraw::Draw(this);
  22. }
  23.  
  24. void Edit()
  25. {
  26. TEdit::Edit(this);
  27. }
  28. };
  29. int main()
  30. {
  31.  
  32. }
  33.  
I will post again later.
Dec 7 '07 #2

weaknessforcats
Expert Mod 5K+
P: 9,197
If your container has CBase* for the data, then all methods you can call have to be handled by the base class.

That means,

a) your virtual functions should be private so when a public base method is called, it can all the private method to don the work. The private method is overriden by the derrived class so it ti actually the derived method that is executed. The separates the interface from the implementation. Check out the design pattern called Template Method

b) all virtual methods of the derived class should be private

c) if a derived class has methods beyond the base class, then you use a visitor.

d) your CBase that this not a template won't work when GetValue() is a termplate method due to the different return types. Thhis forces CBase to be a template as well.
Dec 8 '07 #3

Post your reply

Sign in to post your reply or Sign up for a free account.