How to initialise member variable in template construction

A

Angus

I am trying to set the strategy (algorithm) used in a context by
template. Here is my context class (which is incorrectly
implemented):
template <class TStrategy>
class Context //TStrategy is the algorithm
{
private:
TStrategy * strategy_; //knows about StrategyInterface

public:
void execute() const
{
strategy_->execute();
}
};

The strategies:
class StrategyInterface
{
public:
virtual void execute() const = 0; //abstract class - interface
only
};

//the actual concrete algorithms
class ConcreteStrategyA: public StrategyInterface
{
public:
virtual void execute() const
{
cout << "Called ConcreteStrategyA execute method" << endl;
}
};


And I want to do something like this:
Context<ConcreteStrategyA> contextD;
contextD.execute();

But I need to initialise the context data member properly. how do I
do that?

Angus
 
F

Francesco S. Carta

I am trying to set the strategy (algorithm) used in a context by
template. Here is my context class (which is incorrectly
implemented):
template<class TStrategy>
class Context //TStrategy is the algorithm
{
private:
TStrategy * strategy_; //knows about StrategyInterface

public:
void execute() const
{
strategy_->execute();
}
};

The strategies:
class StrategyInterface
{
public:
virtual void execute() const = 0; //abstract class - interface
only
};

//the actual concrete algorithms
class ConcreteStrategyA: public StrategyInterface
{
public:
virtual void execute() const
{
cout<< "Called ConcreteStrategyA execute method"<< endl;
}
};


And I want to do something like this:
Context<ConcreteStrategyA> contextD;
contextD.execute();

But I need to initialise the context data member properly. how do I
do that?

I'm not sure about "how" you would do that, but I know "where" you
should do that: in a constructor. There is none in the code you posted, why?
 
A

Angus

I'm not sure about "how" you would do that, but I know "where" you
should do that: in a constructor. There is none in the code you posted, why?

--
  FSC -http://userscripts.org/scripts/show/59948
 http://fscode.altervista.org-http://sardinias.com- Hide quoted text -

- Show quoted text -

I guess I just need to add this:
Context(){ strategy_ = new TStrategy; }
~Context() { delete strategy_; }

Could I do it without using the heap?
 
F

Francesco S. Carta

I guess I just need to add this:
Context(){ strategy_ = new TStrategy; }
~Context() { delete strategy_; }

Could I do it without using the heap?

Sure, just change the private "TStrategy * strategy_;" member to
"TStrategy strategy_;" and change the "->" accesses to the "." notation.

If TStrategy needs some parameter passed to its constructor, use the
initialization list, for example:

Context() : strategy_(42) {}

or also:

Context(sometype param) : strategy_(param) {}

depending on the various details.

From there on, every Context will have a TStrategy instance as a data
member, which will be destroyed along with the Context instance that
contains it.

If that's not what you need, you can get along with the dynamic
allocation as you have posted, it all depends on your needs and the
actual implementation of the various parts.
 
R

red floyd

I guess I just need to add this:
Context(){ strategy_ = new TStrategy; }
~Context() { delete strategy_; }

Could I do it without using the heap?

Not if you store a pointer, You defined stategy_ as a TStrategy*.

You could go with a straight-up strategy member.

template <class TStrategy>
class Context //TStrategy is the algorithm
{
private:
TStrategy strategy_; //knows about StrategyInterface

public:
void execute() const
{
strategy.execute();
}

};

Then there's no allocation needed, and strategy_ is automatically
constructed.
 
A

Angus

Not if you store a pointer, You defined stategy_ as a TStrategy*.

You could go with a straight-up strategy member.

template <class TStrategy>
class Context //TStrategy is the algorithm
{
    private:
        TStrategy strategy_;  //knows about StrategyInterface

    public:
        void execute() const
        {
            strategy.execute();
        }

};

Then there's no allocation needed, and strategy_ is automatically
constructed.- Hide quoted text -

- Show quoted text -

That's interesting I tried that:
template <class TStrategy>
class Context //TStrategy is the algorithm
{
private:
TStrategy strategy_; //knows about StrategyInterface

public:
void execute() const
{
strategy_.execute();
}
};

And it works without my defining a constructor. I assume the compiler
is constructing strategy_ somehow behind the scenes. Could I create
my own constructor explicitly? What would it look like?
 
F

Francesco S. Carta

Not if you store a pointer, You defined stategy_ as a TStrategy*.

That's not necessarily true. One can get advantage from pointers and
references to delay or completely omit expensive constructions if not
immediately needed or if not needed at all, still avoiding to use
dynamic allocation.

Given:

class Expensive {
public:
Expensive() {
// some expensive init here
}
void execute() const {
//...
}
private:
// some expensive data here
};

One could do:

class Delayed {
public:
Delayed() : expensive(0) {}
void execute() const {
if (!expensive) set_expensive();
expensive->execute();
}
private:
mutable Expensive* expensive;
void set_expensive() const {
static Expensive exp;
expensive = &exp;
}
};

Although I would maybe implement it so:

class Delayed {
public:
void execute() const {
expensive().execute();
}
private:
Expensive& expensive() const {
static Expensive exp;
return exp;
}
};
 
F

Francesco S. Carta

That's interesting I tried that:
template<class TStrategy>
class Context //TStrategy is the algorithm
{
private:
TStrategy strategy_; //knows about StrategyInterface

public:
void execute() const
{
strategy_.execute();
}
};

And it works without my defining a constructor. I assume the compiler
is constructing strategy_ somehow behind the scenes. Could I create
my own constructor explicitly? What would it look like?

Do you mean a constructor for Context? If you have nothing in particular
to do, you can omit it as shown in the code above, as the compiler will
generate the trivial constructor for you.

The above works because your TStrategy is a type that can be
default-initialized. Assume that TStrategy cannot be
default-initialized, e.g.

class TStrategy {
public:
TStrategy(int i) : data(i) {}
void execute() const {
// use data
}
private:
int data;
};


Assuming the above, you cannot create an instance with "TStrategy ts;",
but you need something like "TStrategy ts(42);", but you cannot when
declaring normal data members (because they cannot be initialized in
their declarations), so, in your Context class, you'd need a constructor
like the one I posted elsethread:

Context() : strategy_(42) {}

Nothing more than that, in a simple case like the one I depicted.

Though, in your case, that seems to be unneeded.
 
F

Francesco S. Carta

That's not necessarily true. One can get advantage from pointers and
references to delay or completely omit expensive constructions if not
immediately needed or if not needed at all, still avoiding to use
dynamic allocation.

Given:

class Expensive {
public:
Expensive() {
// some expensive init here
}
void execute() const {
//...
}
private:
// some expensive data here
};

One could do:

class Delayed {
public:
Delayed() : expensive(0) {}
void execute() const {
if (!expensive) set_expensive();
expensive->execute();
}
private:
mutable Expensive* expensive;
void set_expensive() const {
static Expensive exp;
expensive = &exp;
}
};

Although I would maybe implement it so:

class Delayed {
public:
void execute() const {
expensive().execute();
}
private:
Expensive& expensive() const {
static Expensive exp;
return exp;
}
};

Of course, the above achieves a different target from the dynamic
allocation method and from the has-a idiom, as all the Delayed instances
will share the same Expensive instance. That was just an example to
illustrate my point.
 

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
473,754
Messages
2,569,527
Members
44,999
Latest member
MakersCBDGummiesReview

Latest Threads

Top