Attribute Setting Methods

K

kjell

Hi,

I wonder if someone may have a solution to a small problem I'm
experiencing with a C++ program? I'm have two classes in my
application that provides methods for setting parameters in the
classes. These methods returns a pointer to the class itself so that
you can use the return value to call another attribute setting method
on the same line. This is what my program look like:

#include <iostream>



using namespace std;



class CBase

{

public:

CBase* SetParameterA(const int nA)

{

m_nA = nA;

return this;

};



private:

int m_nA;

};




class CSub: public CBase

{

public:

CSub* SetParameterB(const int nB)

{

m_nB = nB;

return this;

};



private:

int m_nB;

};




main()

{

CSub* pMyInstance = new CSub();

pMyInstance->SetParameterB(1)->SetParameterA(2);

delete pMyInstance;

}


The problem is that if I call SetParameterA() before SetParameterB()
I get a compiler error. I change the third line from the end to:

pMyInstance->SetParameterA(2)->SetParameterB(1);


When I compile the program I get the following error:

> g++ test.cc

test.cc: In function 'int main()':

test.cc:37: error: 'class CBase' has no member named 'SetParameterB'


This is because SetParameterA() returns a pointer to CBase and CBase
does not have a method SetParameterB().

So I'm trying to find a solution to this problem.

One thing that I could do is make the method SetParameterA()
polymorphic, override it in CSub, call the SetParameterA() method in
base class and then type cast the return pointer. The problem with
this approach is that I would have to write wrappers for all methods
in the base class CBase in the derived class CSub.

Would you by any chance have a more elegant solution to this problem?

Thanks for you help,
Kjell
 
S

Salt_Peter

Hi,

I wonder if someone may have a solution to a small problem I'm
experiencing with a C++ program? I'm have two classes in my
application that provides methods for setting parameters in the
classes. These methods returns a pointer to the class itself so that
you can use the return value to call another attribute setting method
on the same line. This is what my program look like:

Why mess with pointers when you don't have to?
Why not set both paramters with a single function call?
#include <iostream>

using namespace std;

class CBase

{

public:

CBase* SetParameterA(const int nA)

{

m_nA = nA;

return this;

};

remove that semicolon, its a definition
private:

int m_nA;

};

class CSub: public CBase

{

public:

CSub* SetParameterB(const int nB)

{

m_nB = nB;

return this;

};

private:

int m_nB;

};

main()

int main()
{

CSub* pMyInstance = new CSub();

pMyInstance->SetParameterB(1)->SetParameterA(2);

delete pMyInstance;

}

The problem is that if I call SetParameterA() before SetParameterB()
I get a compiler error. I change the third line from the end to:

pMyInstance->SetParameterA(2)->SetParameterB(1);

When I compile the program I get the following error:


test.cc: In function 'int main()':

test.cc:37: error: 'class CBase' has no member named 'SetParameterB'

This is because SetParameterA() returns a pointer to CBase and CBase
does not have a method SetParameterB().

So I'm trying to find a solution to this problem.

The solution is to change the design. Provide parametized (and maybe
default) constructors.
instead of accesing objects through endless pointer redirections,
change the object directly using its interface (accessors and
mutators). You can modify the base and derived counterpart with a
single call.
One thing that I could do is make the method SetParameterA()
polymorphic, override it in CSub, call the SetParameterA() method in
base class and then type cast the return pointer. The problem with
this approach is that I would have to write wrappers for all methods
in the base class CBase in the derived class CSub.

Would you by any chance have a more elegant solution to this problem?

Thanks for you help,
Kjell


class Base
{
int m_n;
public:
Base(const int n) : m_n(n) { }
void setbase(const int n)
{
m_n = n;
}
};

class Sub: public Base
{
int m_n;
public:
Sub(const int n, const int b) : Base(b), m_n(n) { }
void setsub(const int n)
{
m_n = n;
}
void setboth(const int n, const int b)
{
Base::setbase(b);
m_n = n;
}
};

int main()
{
Sub instance(1,2);
instance.setboth(2,3);
instance.setbase(4);
instance.setsub(5);
}

How many pointers do you see?
 
D

Daniel T.

I wonder if someone may have a solution to a small problem I'm
experiencing with a C++ program? I'm have two classes in my
application that provides methods for setting parameters in the
classes. These methods returns a pointer to the class itself so that
you can use the return value to call another attribute setting method
on the same line.

This isn't SmallTalk... There are situations where this sort of idiom is
useful in C++, this isn't one of them. Make your setters return 'void'.

Use setters and constructors like Salt_Peter suggested.
 
J

James Kanze

This isn't SmallTalk... There are situations where this sort
of idiom is useful in C++, this isn't one of them. Make your
setters return 'void'.

I'm not sure why. There are three common idioms for setters in
C++:

-- Returning void. This is the simplest for the implementor.

-- Returning a reference to self. This allows chaining:
obj.setA( newA ).setB( newB )...

-- Returning the old value. This allows restoring it by the
user:
A oldA = obj.setA( newA ) ;
// ...
obj.setA( oldA ) ;

Of the three, the first is probably the least useful.

His problem is really a design problem. Client interfaces in
C++ should be complete: if the derived class wants to support
setA, in addition to setB, then it really has to declare it. In
some cases, it's a bit awkward, but the additional type safety
provided by static checking is worth it. So his derived class
would become something like:

class Sub : public Base
{
public:
Sub& setB( int newB ) { /* ... */ }
Sub& setA( int newA )
{
Base::setA( newA ) ; return
*this ;
}
// ...
} ;

Obviously, if Base is a fairly complex interface, and Sub just
adds one simple function, this can be a bit painful, but it's
really the only clean solution.

(For the original poster: you really should return a reference
when chaining---it can't be null. And Microsoft uses the
convention of CXxx for classes in MFC, so you should probably
avoid it, to avoid risking a collision if ever your code is used
with MFC.)
 

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,968
Messages
2,570,150
Members
46,697
Latest member
AugustNabo

Latest Threads

Top