Sign in to follow this  
Boku San

[C++]Modifying access specification in derived classes

Recommended Posts

I'm not sure if maybe I have an old or outdated reference to the standard, but it looks as though users are allowed to modify access levels of virtual functions in derived classes. For those that don't care to read that long-winded sentence, apparently this is completely valid:
class Base {
public:
  virtual void foo() { std::cout << "Base"; }
};

class Derived : public Base {
private:
  void foo() { std::cout << "Derived"; } //implements foo() as private method
};

Base* obj = new Base;
obj->foo(); //prints "Base"
obj = new Derived; //here's where it gets tricky
obj->foo(); //calls private function foo() and prints "Derived"
...


That just seems like a horrible crime against...I dunno, Jesus or something. When would this be useful? Is this behavior even standard? Is anyone going to care to respond to this post? EDIT: Apologies for the double post, internet is the suck.

Share this post


Link to post
Share on other sites
Heh.

Well, I can think of one somewhat contrived example:

class person //an interface
{
public:
virtual void dance( void ) = 0;
virtual void moonwalk( void ) = 0;
virtual void program( void ) = 0;

virtual bool can_dance( void ) const = 0;
virtual bool can_moonwalk( void ) const = 0;
virtual bool can_program( void ) const = 0;

virtual const char * name( void ) const = 0;
};

class Mike : public person
{
private:
void moonwalk( void ) {
throw i_cant_moonwalk();
}
public:
bool can_moonwalk( void ) const {
return false;
}
void dance( void ) {
cout << "Mike is doing the robot!!" << endl;
}
bool can_dance( void ) const {
return true;
}
void program( void ) {
cout << "Mike is programming!!" << endl;
}
bool can_program( void ) const {
return true;
}
const char * name( void ) const {
return "Mike";
}
};






Now, if we have a collection of people:

std::vector< person * > people;

We could ask them all to dance or moonwalk:

void dance_if_you_can( person * p ) {
if ( p->can_dance() )
p->dance();
}

void dance_dance_dance( person * p ) {
try {
p->dance();
} catch( i_cant_dance ) {
cerr << "Ha ha, " << p->name() << " can't dance!!" << endl;
}
}

std::for_each( people.begin() , people.end() , std::fun_ptr( &dance_if_you_can ) );
std::for_each( people.begin() , people.end() , std::fun_ptr( &dance_dance_dance ) );






But we'll get a compiler error letting us know we've made a mistake if we tell Mike to moonwalk:

Mike mike;
mike.moonwalk(); //compiler error: Mike can't moonwalk!!!


This is good, because we're probably catching a bug. We can't allways check at compile time if the person can moonwalk, though:

std::vector< person * > people;
people.push_back( new Mike );
people.push_back( new Doug );
people.push_back( new Noel );
std::random_shuffle( people.begin() , people.end() );
person * p = people.first();
p->moonwalk(); //this might ask Mike, Doug, or Noel to moonwalk... we don't know.

Share this post


Link to post
Share on other sites
Quote:
Original post by Boku San
I'm not sure if maybe I have an old or outdated reference to the standard, but it looks as though users are allowed to modify access levels of virtual functions in derived classes.

For those that don't care to read that long-winded sentence, apparently this is completely valid:
*** Source Snippet Removed ***

That just seems like a horrible crime against...I dunno, Jesus or something. When would this be useful? Is this behavior even standard? Is anyone going to care to respond to this post?

EDIT: Apologies for the double post, internet is the suck.



There are a number of instances where that might be the exact behavior you want to enforce. For instance:


You create a base class BUT you do not want to allow users to directly instantiate an object of that type. You do not want to use pure virtuals for whatever reason so you declare the constructor as "protected"....


class Base {
protected:
Base();

public:
DefaultMethods();
};



Next you declare a class that inherits from Base declaring the constructor as public...

class Child : public Base {
public:
Child();
};


Base *b = new Base(); // Fails
Child *c = new Child(); // Works



The same thing applies to virtual methods. You may find a situation where you need to create a container to hold specific objects. That container needs to access certain methods but can't because they are protected. In this case you derive from the base class and provide implementation for the methods the container needs access to along with all other requirements the base class may expect or require.


Keep in mind that just because you CAN do it doesn't mean you SHOULD do it.

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