|
-
July 21st, 2004, 03:33 PM
#1
protected members in base class
I have to roll up this topic again, sorry.
In this thread, someone said it would be dubious practice to declare data members 'protected' in a base class.
But what if I have an abstract base class which only describes how child classes should look? Consider a base class Vehicle. All vehicles have an attribute speed. I MUST make that attribute protected, or otherwise a car (which is a vehicle) has no speed. I know you came off with some code showing that it IS dangerous for specific data to make it protected, but when I WANT the data to be inherited (and altered at some point) by derivates, there should be nothing "dubious" bout that. That's what protected is for, isn't it?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 21st, 2004, 03:42 PM
#2
Well, don't forget that interface is derived too.
You can use a private member in your abstract class, and provide get/set/whatever virtual functions that access this member.
Ofcoure, its up to you whether to provide the interface as public or protected.
[edit] to be more accurate, when using polymorphism the virtual interface
is inherited.
Last edited by Guysl; July 21st, 2004 at 03:45 PM.
**** **** **** **** **/**
-
July 23rd, 2004, 12:32 AM
#3
But 'speed' is also a property of the child classes. Why should only Vehicle have a certain speed attribute?
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 23rd, 2004, 12:48 AM
#4
Let me give an example:
Code:
class Vehicle
{
public:
Vehicle( int sp ): speed( sp ) {}
virtual ~Vehicle() {}
protected:
int speed;
};
class Car: public Vehicle
{
public:
Car( int sp ): Base( sp )
{
if( speed > 200 )
{
cout << "Too fast!" << endl;
speed = 50;
}
}
};
What's wrong with that? Speed is an attribute which all cars have. The example isn't chosen too well because speed should only be set once, but what if data members are supposed to be altered by the child classes? Is your suggestion to do that:
Code:
class Vehicle
{
public:
Vehicle( int sp ): speed( sp ) {}
virtual ~Vehicle() {}
virtual int GetSpeed() { return speed; }
virtual void SetSpeed( int s ) { speed = s; }
private:
int speed;
};
class Car: public Vehicle
{
public:
Car( int sp ): Base( sp )
{
if( GetSpeed() > 200 )
{
cout << "Too fast!" << endl;
SetSpeed( 50 );
}
}
};
Is that what you mean?
Last edited by matthias_k; July 23rd, 2004 at 12:56 AM.
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 23rd, 2004, 12:56 AM
#5
forgot adding a 'virtual' to the getter/setter to allow dynamic binding.
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 23rd, 2004, 01:19 AM
#6
 Originally Posted by matthias_k
Let me give an example:
Code:
class Vehicle
{
public:
Vehicle( int sp ): speed( sp ) {}
virtual ~Vehicle() {}
protected:
int speed;
};
class Car: public Vehicle
{
public:
Car( int sp ): Base( sp )
{
if( speed > 200 )
{
cout << "Too fast!" << endl;
speed = 50;
}
}
};
What's wrong with that?
What if you decide to rename your "speed" variable to "nSpeed", or "m_nSpeed" or you do something else that calculates the speed? You've broken every child class that mentions anything about "speed", since the variable or method of calculation has changed.
By having this as a function (SetSpeed()), you can change the implementation in the base class without affecting the derived classes whatsover.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; July 23rd, 2004 at 01:32 AM.
-
July 23rd, 2004, 01:02 PM
#7
Also, how can you guarantee that the speed variable in your base class will not be corrupted by a derived class? Can you guarantee that whatever value a derived class sets the speed variable, your base class will still work correctly? What if someone decides to do this:
Code:
class Rocket : public Vehicle
{
public:
Rocket()
{ speed = -500; }
};
Does it make sense for a vehicle to have a negative speed? How can your base class check for this if speed was declared protected?
Last edited by cma; July 23rd, 2004 at 01:04 PM.
Hungarian notation, reinterpreted? http://www.joelonsoftware.com/articles/Wrong.html
-
July 23rd, 2004, 01:42 PM
#8
The advantages of set/get functions are:
1) A getter can return either a copy or a const reference to prevent corruption.
2) A setter can do sanity checking on a supplied value (and, thus, reduce code duplication).
For example, suppose your vehicle class has a current speed and a max speed. Anything that wants to set the current speed has to check against the maximum speed. By putting in a setter function, you localise that check. And, of course, the cry "but the spec doesn't require that" turns out to be a magical incantation that guarantees that the spec will change in less than a New York second.
3) You can treat derived values (i.e. values that do not correspond to a member, but are computed on-the-fly) the same way as direct values. Corollary: you can remove a data member if you find that it becomes redundant.
4) (Related to 3) You are at liberty to alter the representation of the attribute without affecting anyone else.
Don't get seduced by the argument "well, what's the difference?" Today, there may be no difference at all except for a bit more typing. Next month, when the client changes their mind yet again, it could make all the difference. It's about defensive programming: why throw away potential future advantage for the sake of a few keystrokes now.
Don't forget, the protected section of your class is to derived classes what the public section is to the rest of the world - it's an interface that defines your class's capabilities. Treat the protected section the same way you treat the public section: it's just the target audience that's different.
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
July 23rd, 2004, 01:51 PM
#9
Does it make sense for a vehicle to have a negative speed? How can your base class check for this if speed was declared protected?
A setter can do sanity checking on a supplied value (and, thus, reduce code duplication).
Hmm, if the setter is virtual (which it should be as someone said above), derivates can still override it and screw everything up. The base class still has no control whatsoever.
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 23rd, 2004, 02:13 PM
#10
Hmm, if the setter is virtual (which it should be as someone said above), derivates can still override it and screw everything up. The base class still has no control whatsoever.
Not really. The override virtual functions can access a base member using
the interface tha base itself provide. If it provides a setter, you can't skip
its checks and limitations.
**** **** **** **** **/**
-
July 23rd, 2004, 06:39 PM
#11
Hmm, if the setter is virtual (which it should be as someone said above), derivates can still override it and screw everything up. The base class still has no control whatsoever.
Then show an example of this using the second code in the post with the virtual accessor and mutator member functions.
Hungarian notation, reinterpreted? http://www.joelonsoftware.com/articles/Wrong.html
-
July 24th, 2004, 02:47 AM
#12
 Originally Posted by matthias_k
Hmm, if the setter is virtual (which it should be as someone said above), derivates can still override it and screw everything up. The base class still has no control whatsoever.
In this case there is absolutely no need and every reason not to make the setter/getter virtual. The only time that the base class should define a virtual setter or getter is when the attribute is logically part of the public interface (or is needed by a base class function), but the base class cannot (for whatever reason) provide an implementation for that attribute. It's then up to each derived class to provide the implementation. Encapsulation maintained; polymorphism achieved,
Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
-- Sutter and Alexandrescu, C++ Coding Standards
Programs must be written for people to read, and only incidentally for machines to execute.
-- Harold Abelson and Gerald Jay Sussman
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell
-
July 24th, 2004, 03:11 AM
#13
Okay you've convinced me one more time
- Matthias
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off." - Bjarne Stroustrup
-
July 24th, 2004, 05:54 AM
#14
Originally posted by me:
The override virtual functions can access a base member using
the interface tha base itself provide. If it provides a setter, you can't skip
its checks and limitations.
That is what I meant:
Code:
class Base{
public:
Base(int val) { defaultSetter(val); }
virtual void setter(int val) = 0;
protected:
void defaultSetter(int val)
{
m_Base = (val>100 ? 100 : val);
}
private:
int m_Base;
};
//=================================
class Derived1 : public Base{
public:
Derived1(int val) : Base(val) {}
void setter(int val)
{
if(val < 10)
defaultSetter(10);
else
if(val > 80)
defaultSetter(80);
else
defaultSetter(val);
}
};
//=================================
class Derived2 : public Derived1{
public:
Derived2(int val) : Derived1(val) {}
void setter(int val)
{
if(val < 50)
defaultSetter(50);
else
if(val > 60)
defaultSetter(60);
else
defaultSetter(val);
}
};
Last edited by Guysl; July 24th, 2004 at 06:05 AM.
**** **** **** **** **/**
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|