class that have a member of type that's derived from it

M

Mirko Puhic

Is there a way to properly do this?



struct Derived;

struct Base{
Derived der;
};

struct Derived: public Base{

};
 
A

Alan Johnson

Mirko said:
Is there a way to properly do this?



struct Derived;

struct Base{
Derived der;
};

struct Derived: public Base{

};

This is called the Curiously Recurring Template Pattern (honestly).

template <typename DerivedType>
struct Base
{
DerivedType der ;
} ;

struct Derived : public Base<Derived>
{
} ;
 
A

Alan Johnson

Alan said:
This is called the Curiously Recurring Template Pattern (honestly).

template <typename DerivedType>
struct Base
{
DerivedType der ;
} ;

struct Derived : public Base<Derived>
{
} ;

Except, I should have run it through a compiler before posting. That
won't work. And object of type Derived can't contain a member (directly
or via inheritance) of type Derived, because that member would, of
course, also contain an member of type Derived, which would also ... you
see the problem.

What you CAN do is have a pointer or reference. Example:
struct Derived ;

template <typename DerivedType>
struct Base
{
DerivedType * der ;
} ;

struct Derived : public Base<Derived>
{
} ;
 
M

Mirko Puhic

Alan said:
Except, I should have run it through a compiler before posting. That
won't work. And object of type Derived can't contain a member (directly
or via inheritance) of type Derived, because that member would, of
course, also contain an member of type Derived, which would also ... you
see the problem.

What you CAN do is have a pointer or reference. Example:
struct Derived ;

template <typename DerivedType>
struct Base
{
DerivedType * der ;
} ;

struct Derived : public Base<Derived>
{
} ;

I see. Pointer will do. But in that case I think there's no need to use
a template:


struct Derived;

struct Base{

Derived * der;

};

struct Derived: public Base{

};
 
A

Alan Johnson

Mirko said:
I see. Pointer will do. But in that case I think there's no need to use
a template:


struct Derived;

struct Base{

Derived * der;

};

struct Derived: public Base{

};

True, though there are still times when that template pattern is useful.
Consider if you wanted to make a utility from which people could
derive to make their class into a linked list node. It might be useful
to do something like:

template <typename T>
struct Linkable
{
T * next ;
} ;

class MyType : public Linkable<MyType>
{
// ...
} ;

Another case is when you need each derived type to have its own copy of
static members.

template <typename T>
struct Base
{
// Note that this class doesn't actually use its template parameter.
static SomeType value ;
} ;

// A::value and B::value are separate objects.
class A : public Base<A> {}
class B : public Base<B> {}


More exotic uses arise in various template metaprogramming techniques.
 
M

Mirko Puhic

Alan said:
True, though there are still times when that template pattern is useful.
Consider if you wanted to make a utility from which people could derive
to make their class into a linked list node. It might be useful to do
something like:

template <typename T>
struct Linkable
{
T * next ;
} ;

class MyType : public Linkable<MyType>
{
// ...
} ;

Another case is when you need each derived type to have its own copy of
static members.

template <typename T>
struct Base
{
// Note that this class doesn't actually use its template parameter.
static SomeType value ;
} ;

// A::value and B::value are separate objects.
class A : public Base<A> {}
class B : public Base<B> {}


More exotic uses arise in various template metaprogramming techniques.

Thenks, having a separate static member for each derived class seems
really useful.
Only problem with using pointer is that you can't create actual object
in the constructor because it would send the program into infinite
recursion.
 
W

werasm

Mirko said:
Thenks, having a separate static member for each derived class seems
really useful.
Only problem with using pointer is that you can't create actual object
in the constructor because it would send the program into infinite
recursion.

You don't even need the seperate member in the base using CRTP. You
already have the implicit this pointer that can be casted to the
derived.

template <class DerivedT>
struct Base
{
void foo()
{
dynamic_cast<Derived*>(this)->doFoo();
}
};

class Derived : public Base<Derived>
{
public:
void doFoo(){}
};

I still can't see how you can get recursion... elaborate please.

Regards,

W
 
M

Mirko Puhic

werasm said:
I still can't see how you can get recursion... elaborate please.

In case I want Derived object to be created in Base constructor:


class Derived;

class Base{
public:
Base(){
der = new Derived();
}
Derived * der;

};

class Derived: public Base{

}
 
M

Mirko Puhic

Mirko said:
In case I want Derived object to be created in Base constructor:


class Derived;

class Base{
public:
Base(){
der = new Derived();
}
Derived * der;

};

class Derived: public Base{

}

I mean it's the same "recursion" problem as with using the type Derived
as an actual member (not pointer) of the class Base.
 
W

werasm

Mirko said:
In case I want Derived object to be created in Base constructor:

Why would you want do to that? Base can only be constructed upon
instantiating derived anyway....

Derived d;//...

constructs base implicitly, and the pointer in base becomes a valid
derived...

template <class DerivedT>
struct Base
{
Derived* getDerived(){ return dynamic_cast<DerivedT*>(this); }
};

class Derived : public Base<Derived>{ /*...*/ };

Derived::Derived
: Base<Derived>()
{
//From this point onwards, we can no obtain valid derived pointer...
}

int main()
{
Derived d;
Base<Derived>* pb( &d );
pb->getDerived()->foo();//would work assuming Derived had member
function foo...

return 0;
}
class Derived;

class Base{
public:
Base(){
der = new Derived();
}
Derived * der;

};

You don't need to assign a new Derived to der, you don't even need a
der as this is implicitly already a pointer to the derived class if you
cast it, provided Derived is truly inherited from Base (which one can
enforce, btw).

Kind regards,

Werner
 

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

No members online now.

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top