Sign in to follow this  
johnnyBravo

c++, How to make an inherited function not accessible?

Recommended Posts

Hi, with c++, I'm doing a bit of inheritance. And I've got two classes(extremely cut down versions) which are both used through out the app(so no abstract classes here):
class OutputLayer {
public:
    void calcErrors(float *desiredOutputs);
};

class HiddenLayer:public OutputLayer{
public:
    void calcErrors();
};


See how I have a calcErrors function for both classes, I don't want the calcErrors(float *desiredOutputs) function from the OutputLayer class to be accessible from the HiddenLayer class. To do this would I just do this:
class OutputLayer {
public:
    virtual void calcErrors(float *desiredOutputs);
    //or would I add = 0 to the end aswell? eg..
    virtual void calcErrors(float *desiredOutputs) = 0;
};


Thanks

Share this post


Link to post
Share on other sites
When you say "...accessible from the HiddenLayer class." do you mean the HiddenLayer class itself, or users of the HiddenLayer class?
Unless you make it private in OutputLayer it will be accessible in HiddenLayer.

If you want to it to be unaccessible to users of HiddenLayer you can use an esoteric using clause as such:

class OutputLayer {
public:
void calcErrors(float *desiredOutputs);
};

class HiddenLayer : public OutputLayer{
public:
void calcErrors();
private:
using OutputLayer::calcErrors;
};





If you want to give users a HiddenLayer object and have them treat it as an OutputLayer object blissfully unaware of the hiddern layer, then you need to use a virtual function and the function signatures need to match.

Share this post


Link to post
Share on other sites
I want it hidden from the users of the HiddenLayer class,

So a user using HiddenLayer can't use the:
void calcErrors(float *desiredOutputs);

but can use:
void calcErrors();

And users of the OutputLayer can use the:
void calcErrors(float *desiredOutputs);

So this using clause(using OutputLayer::calcErrors), will disallow the use of the inherited calcErrors?

Thanks


Share this post


Link to post
Share on other sites
There are very few situations where hiding an inherited function make sense, IMO (besides private inheritence, in which case it's allready hidden). There are a few, however.

Usually, these are for situations where it may be an error to call a member function in certain situations, and allways for certain derivations.

To take a rather contrived example. We have an interface for "food":

struct ifood {
virtual bool ediable() const = 0;
virtual void eat() = 0;
virtual bool chewable() const = 0;
virtual void chew() = 0;
};


With most normal foods, they are both ediable and chewable:

struct apple : ifood {
bool ediable() const {
return true;
}
void eat() {
cout << "Yum, an apple a day keeps the doctor away!" << endl;
}
bool chewable() const {
return true;
}
void chew() {
cout << "Chew chew chew away on that apple" << endl;
}
};


However, certain specializations might not be. It's hard to chew soda, for example, so we might have it throw an exception if someone mistakenly calls chew():

struct idrink : ifood {
bool chewable() const {
return false;
}
void chew() {
throw std::runtime_error( "Cannot chew an idrink!" );
}
};

struct full_throttle : idrink {
bool ediable() const {
return true;
}
void eat() {
cout << "Gulp gulp gulp, gotta love them energy drinks!" << endl;
}
};


All good, right? Well not really, we've done damage control here, but nobody should really be chewing idrinks in the first place. 99% of the time this is the smell of a broken class heiarchy. Really, it's a brittle interface - we shouldn't be storing idrinks and ifoods together in the first place. This way, we know we can ALLWAYs eat() it, or ALLWAYs know we can't (ditto with chew).

But, often, one has to deal with less than perfect code. Prehaps you don't know the best solution, or are mantaining a legacy solution. You _can_ make an inherited function private - it won't save you all the time, but it'll catch mistakes some of the time. Let's go back to idrink and make it's chew() private:

struct idrink : ifood {
bool chewable() const {
return false;
}
private:
void chew() {
throw std::runtime_error( "Cannot chew an idrink!" );
}
};


And now let's have ourselves a chewing contest.

int main () {
apple my_apple;
full_throttle my_drink;

my_apple.chew();
my_drink.chew();
}


In this case, with my compiler at least, I get a compile error on the my_drink.chew() line: "../main.cc:34: error: `virtual void idrink::chew()' is private"

Joy! It worked! Kinda.

It's not foolproof. If you're ever accessing my_drink through the base class, you've lost any protection you may have had:

int main () {
apple my_apple;
full_throttle my_drink_data;
ifood & my_drink = my_drink_data;

my_apple.chew();
my_drink.chew();
}


This compiles fine. Also, this private trickery can play hell with perfectly well behaved template code:

template < typename food_type >
void chew_it_if_you_can( food_type & food ) {
if ( food.chewable() ) food.chew();
}

int main () {
apple my_apple;
full_throttle my_drink;
ifood & my_food_drink;

chew_it_if_you_can( my_apple ); //OK, chews it
chew_it_if_you_can( my_drink ); //ERROR: Can't access chew() - even though we never call it, the compiler dosn't let us get away with this.
chew_it_if_you_can( my_food_drink ); //OK, dosn't do anything
}


You have been warned/informed/preached at.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this