Simple inheritance-template question

C

crea

I cannot find solution to this:

Here is the structure:

template <class T> class Data
{
public:
T p;
};

class AA
{
public:
// here I would like to have a data member: m_data
};

class BB : public AA
{
public:
};

If an object is create from AA then I want it to have member data object
created like this:
Data<int> m_data;

But if an object is created from BB then I want:

Data<string> m_data;

How to create a member data variable according to what class the object is
created from? Is this even possible?



Point is that for BB I want a data member of type "string" and for AA I want
a data member of type "int". And in both cases the data member name is
"m_data" and it is located in the class AA.
 
I

Ian Collins

I cannot find solution to this:

Here is the structure:

template<class T> class Data
{
public:
T p;
};

class AA
{
public:
// here I would like to have a data member: m_data
};

class BB : public AA
{
public:
};

If an object is create from AA then I want it to have member data object
created like this:
Data<int> m_data;

But if an object is created from BB then I want:

Data<string> m_data;

How to create a member data variable according to what class the object is
created from? Is this even possible?

No, not really. To do so would break the "is a" rule (a BB isn't an
AA). Maybe make Data a union rather than a template?

What problem are you trying to solve?
 
C

crea

Point is that for BB I want a data member of type "string" and for AA I
want a data member of type "int". And in both cases the data member name
is "m_data" and it is located in the class AA.

So it would look something like this:

template <class T> class Data
{
public:
T p;
};

class AA
{
public:
m_data
};

class BB : public AA
{
public:
};

If I create an object from BB:

BB b;

then m_data is created to be string-type (Data class member p becomes
string)

And if I create an object from AA

AA b;

then m_data is created to be int-type (Data class member p becomes int).

Not sure if template is best to acquire this. (Actually in my real program
its not int/string types, but classes where the other one is the parent of
the other one. So I was first thinking of using inheritance +pointers
instead of tamplate:

class Data
{
public:
ParentClass* p;
};

and then just set p to point parent and/or its child class object, and
virtuality would make sure they point to right classes.)
 
C

crea

Ian Collins said:
No, not really. To do so would break the "is a" rule (a BB isn't an AA).
Maybe make Data a union rather than a template?

Thanks, i ll think about this.
What problem are you trying to solve?

Ok, let me put it like it is in my real program:

Holds the data:
struct DataHolder
{

Data* data;

};

Where real Data:
class Data {...};

Then I have a class which uses it:

class AA
{
public:
DataHolder m_data;
};

So now I can get hold of the real data from AA by:
m_data.data;

Now I want to inherit a class from AA:

class BB : public AA
{
public:
};

But for BB I want to use different data -class which is inherited from Data:
class BBData : public Data
{...};

struct DataHolder
{

BBData* data;

};

class AA
{
public:
DataHolder m_data;
};

class BB : public AA
{
public:
};

So the only thing which should change here is the DataHolder::data s type.
It looked like a template type problem. But because BBData is inherited from
Data, maybe virtuality /inheritance could also be used.

So this should be in DataHolder instead of Data if I create an BB object.
How to do this? I was thinking using templates first..
 
C

crea

The problem with union would be, that what if want to inherit 100 classes
later on from AA :). So then I would need to modify this Union 100 times.
Using inheritance or templates I would not need to add anything. Thats why I
would prefer to solve this by inheritance or templates. See my other post
where I describe the problem how it really is.
 
C

crea

This would definitely work:
template <class T> class Data
{
public:
T p;
};

template <class T> class AA
{
public:
Data<T> m_data;
};

template <class T> class BB : public AA
{
public:
};

So I could create object like this:

AA<int> b;
BB<string> b;

Ok, this definitely works, but its a bit difficult to put all of those
templates in all classes. I was thinking that because the only thing I need
here is that BB has different Data::p type than AA, so it could be done
hidden in BB class somehow. So there is no need to tell it when calling:

BB<string> b;

but rather just:
BB b;

I dont think we need to tell the type when creating objects, because the
classes already know what type it should be (if created an object from BB it
ALWAYS has string type and AA ALWAYS has int type - thats the situation).
 
G

Goran

Ok, let me put it like it is in my real program:

Holds the data:
struct DataHolder
{

   Data* data;

};

Where real Data:
class Data {...};

Then I have a class which uses it:

class AA
{
public:
DataHolder m_data;

};

So now I can get hold of the real data from AA by:
m_data.data;

Now I want to inherit a class from AA:

class BB : public AA
{
public:

};

But for BB I want to use different data -class which is inherited from Data:
class BBData : public Data
 {...};

struct DataHolder
{

   BBData* data;

};

class AA
{
public:
DataHolder m_data;

};

class BB : public AA
{
public:

};

So the only thing which should change here is the DataHolder::data s type..
It looked like a template type problem. But because BBData is inherited from
Data, maybe virtuality /inheritance could also be used.

So this should be in DataHolder instead of Data if I create an BB object.
How to do this? I was thinking using templates first..

I would simply make sure (through correct coding) that BB does use
DataHolder that has a pointer to BBData (not "plain" data) and then
use this:

class AA
{
Data& GetData() { assert(m_data.data); return *m_data.data; }
}

class BB : public AA
{
BBData& GetData() { return static_cast<BBData&>(AA::GetData(); }
};

Goran.
 
C

crea

"I would simply make sure (through correct coding) that BB does use
DataHolder that has a pointer to BBData (not "plain" data) and then
use this:

class AA
{
Data& GetData() { assert(m_data.data); return *m_data.data; }
}

class BB : public AA
{
BBData& GetData() { return static_cast<BBData&>(AA::GetData(); }
};

Goran."

I was also thinking that first. But the problem is that inside AA I have
code like:
void AA::DoSomething()

{

....(a lot of code)

m_data.data.Add(new Data());

....(a lot of code)

}



So if I create a BB object and call this DoSomething , then it will create
Data-instance and not BBData. I know I could make DoSomething a virtual
fucntion , but DoSomething is *very* big function so I would rather now copy
all of it to BB. Yes, I could then create a virtual function for only that
"Add"... :

void BB::AddData(..)



and then have virtual in AA:

virtual void AA::AddData(..). So now DoSomething becomes:



void AA::DoSomething()

{

....(a lot of code)

AddData(..);

....(a lot of code)

}

but AA has like 5 different this kind of fucntions. Shall I just create a
virtual function for all of them (5 of them)? I could obviously put them to
be private. But is there any easier way... this is doable, but needs to
override many functions.
 
G

Goran

"I would simply make sure (through correct coding) that BB does use
DataHolder that has a pointer to BBData (not "plain" data) and then
use this:

class AA
{
  Data& GetData() { assert(m_data.data); return *m_data.data; }

}

class BB : public AA
{
  BBData& GetData() { return static_cast<BBData&>(AA::GetData(); }

};

Goran."

I was also thinking that first. But the problem is that inside AA I have
code like:
void AA::DoSomething()

{

...(a lot of code)

m_data.data.Add(new Data());

...(a lot of code)

}

So if I create a BB object and call this DoSomething , then it will create
Data-instance and not BBData. I know I could make DoSomething a virtual
fucntion , but DoSomething is *very* big function so I would rather now copy
all of it to BB. Yes, I could then create a virtual function for only that
"Add"... :

void BB::AddData(..)
and then have virtual in AA:

virtual void AA::AddData(..). So now DoSomething becomes:

void AA::DoSomething()

{

...(a lot of code)

AddData(..);

...(a lot of code)

}

but AA has like 5 different this kind of fucntions. Shall I just create a
virtual function for all of them (5 of them)? I could obviously put them to
be private. But is there any easier way... this is doable, but needs to
override many functions.

(Not private, protected, you need to override).

Overrides seem^^^ to be trivial: create a different object type given
some parameters, so why not?

(^^^: I am guessing that after new Data() you actually put something
useful in that object).

Goran.
 
C

crea

"(Not private, protected, you need to override).

Overrides seem^^^ to be trivial: create a different object type given
some parameters, so why not?"

Yes, this works. Its just that needs to always update both classes if adds
new code for data. Would be handy to have some kind of template which tells
the type of data.

"(^^^: I am guessing that after new Data() you actually put something
useful in that object)."

Yes, its data from the file this objects is filled first and then given as
new parameter.
 
C

crea

Goran said:
but AA has like 5 different this kind of fucntions. Shall I just create a
virtual function for all of them (5 of them)? I could obviously put them
to
be private. But is there any easier way... this is doable, but needs to
override many functions.

"(Not private, protected, you need to override).

Overrides seem^^^ to be trivial: create a different object type given
some parameters, so why not?

(^^^: I am guessing that after new Data() you actually put something
useful in that object)."

I just checked, and actually the only place where I need some kind of
virtual calling is when I do this in couple of places:
m_Data.data.Add(new Data(...));

So the new -operation needs some kind of virtual version. hmmm , maybe just
to create a function NewObject:

in AA:

virtual Data NewObject()

{ return new Data(); }



and then have in BB:

virtual BBData NewObject()

{ return new BBData(); }



so the call in AA goes now:



m_Data.data.Add(NewObject());



What do you think!! Looks like perfect.
 
C

crea

crea said:
virtual BBData NewObject()

{ return new BBData(); }

Only problem I see here is that the class derived from AA now has to
remember to create the NewObject fucntion. I they dont, it will fail. Is
there any way to force the child class to create always this NewObject
function, otherwise there is compile error? If not, there is a human error
possibility here if forgets to implement NewObject function in child
classes.
 
G

Goran

Only problem I see here is that the class derived from AA now has to
remember to create the NewObject fucntion. I they dont, it will fail. Is
there any way to force the child class to create always this NewObject
function, otherwise there is compile error? If not, there is a human error
possibility here if forgets to implement NewObject function in child
classes.

Only if you forget to override __and__ upcast in derived class.

That's why C++-style casting is there IMO: it stands out like a sore
thumb, making you think about it more ;-).

I think you worry too much there. Unless you go completely crazy with
casting, risk should be quite manageable.

Goran.
 
V

Victor Bazarov

This would definitely work:
template<class T> class Data
{
public:
T p;
};

template<class T> class AA
{
public:
Data<T> m_data;
};

template<class T> class BB : public AA

'AA' is missing the template arguments. Won't compile. Did you mean to say

template<class T> class BB : public AA<T>

?
{
public:
};

So I could create object like this:

AA<int> b;
BB<string> b;

You can't create two objects of different types with the same name in
the same scope.
Ok, this definitely works,
Nope.

but its a bit difficult to put all of those
templates in all classes. I was thinking that because the only thing I need
here is that BB has different Data::p type than AA, so it could be done
hidden in BB class somehow. So there is no need to tell it when calling:

BB<string> b;

but rather just:
BB b;

I dont think we need to tell the type when creating objects, because the
classes already know what type it should be (if created an object from BB it
ALWAYS has string type and AA ALWAYS has int type - thats the situation).

V
 
C

crea

Victor Bazarov said:
'AA' is missing the template arguments. Won't compile. Did you mean to
say

template<class T> class BB : public AA<T>

?

yes, sorry... I did not compile the code, so might have errors.
You can't create two objects of different types with the same name in the
same scope.

ye, should be c the other one...

after corrections yes.. :)
 
N

Noah Roberts

So it would look something like this:

template<class T> class Data
{
public:
T p;
};

class AA
{
public:
m_data
};

class BB : public AA
{
public:
};

If I create an object from BB:

BB b;

then m_data is created to be string-type (Data class member p becomes
string)

And if I create an object from AA

AA b;

then m_data is created to be int-type (Data class member p becomes int).

I don't really understand the question so I'll try to answer the various
questions you could be asking. To override m_data it's as easy as

class BB : public AA
{
public:
string m_data; // was declared int in AA.
};

Now though you have a class with two m_data objects in it depending on
scope.

The other thing you seem to be asking is how to declare a member in a
template based on the instantiation parameter type. This can be done
two different ways. Luckily, the two ways can be combined nicely:

template < typename T >
struct member_type { typedef typename T::mem_t type; };

template < >
struct member_type<AA> { typedef int type; };
template < >
struct member_type<BB> { typedef string type; };

template < typename T >
class Data
{
public:
typedef typename member_type<T>::type m_data_t;
m_data_t m_data;
};

Of course, there's a third option which uses mpl::if_ but it would scale
as well as a turd.
 
C

crea

Noah Roberts said:
I don't really understand the question so I'll try to answer the various
questions you could be asking. To override m_data it's as easy as

class BB : public AA
{
public:
string m_data; // was declared int in AA.
};

Now though you have a class with two m_data objects in it depending on
scope.

I think you understand my point... I tried this and it works (I actually
found it myself before, this idea). But is this good programming for sure?
This is all according to c++ rules to do like this? Because now when we are
creating a BB-object then int m_data; - member is also created even though
we never use it for that object. Is this good programming... I am just
thinking. So there is created one member variable that is never used (int
m_data; in AA).

Other than that, this actually would do the job for me.

My point is that: for objects created from BB I want to have a m_data member
created with type string:

Data<string> m_data;

and for objects created from AA I want a m_data member created with type
int:

Data said:
The other thing you seem to be asking is how to declare a member in a
template based on the instantiation parameter type. This can be done two
different ways. Luckily, the two ways can be combined nicely:

template < typename T >
struct member_type { typedef typename T::mem_t type; };

template < >
struct member_type<AA> { typedef int type; };
template < >
struct member_type<BB> { typedef string type; };

template < typename T >
class Data
{
public:
typedef typename member_type<T>::type m_data_t;
m_data_t m_data;
};

I think you might be into something here, but this is quite complex for me
so takes some time to understand this code :). I ll let you know. This might
be even better than your first suggestion because we would not create a
variable which is never used.
 
C

crea

The other thing you seem to be asking is how to declare a member in a
template based on the instantiation parameter type. This can be done two
different ways. Luckily, the two ways can be combined nicely:

template < typename T >
struct member_type { typedef typename T::mem_t type; };

template < >
struct member_type<AA> { typedef int type; };
template < >
struct member_type<BB> { typedef string type; };

template < typename T >
class Data
{
public:
typedef typename member_type<T>::type m_data_t;
m_data_t m_data;
};

Can you then also show my how to use this (in main function)? I am a bit
lost , because seems like its not exatcly the same as my example.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top