• Advertisement
Sign in to follow this  

[C++]Modifying access specification in derived classes

This topic is 4619 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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
Advertisement
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
Sign in to follow this  

  • Advertisement