Thread: Design flaw in C++?

  1. #1
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591

    Design flaw in C++?

    Code:
    class EventHandler
    {
      public: virtual void handleEvent( ) { cout << "default handler" }
    }
    
    class MyEventHandler : public EventHandler
    {
      private: void handleEvent( ) { cout << "my handler" }
    }
    
    void handleEvents( EventHandler *eh )
    {
      eh->handleEvent( );
    }
    
    int main()
    {
      handleEvents( MyEventHandler() );
    }
    To my surprise the private member function is called directly rom a public context!! What is the moral of the story here? That the private keyword is disrespected when you declare a member function sharing the same name as a public one in a base class? I guess I could go with that, otherwise there'd be ambiguity between private Foo::x and public BaseFoo::x within Foo itself. HOWEVER, should the compiler not at least warn me that it's going to drop my privates (so to speak) in this situation!? Seems a tad shady...

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The compiler doesn't know (at least in the general case) that MyEventHandler even exists, so it can't warn you that you are calling a function that is private in the derived class.

    The point of the dynamic polymorphism here is that the dynamic type of eh is determined at run time, not compile time. That means that at compile time, as long as handleEvent is callable from the EventHandler interface then the code is valid.

  3. #3
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Hmm, I see now. I think they could have done a better job with the semantics of the private keyword in this case, but I guess specs are specs for a reason...
    Code:
    11.6 Access to virtual functions [class.access.virt]
    1 The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for
    a function that later overrides it. [ Example:
    class B {
    public :
    virtual int f();
    };
    class D : public B {
    private :
    int f();
    };
    void f()
    {
    Draft
    217 Member access control 11.7 Multiple access
    D d;
    B* pb = & d;
    D* pd = & d;
    pb ->f (); / / OK: B::f() is public,
    / / D::f() is invoked
    pd ->f (); / / error: D::f() is private
    }
    —end example ]

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I think they could have done a better job with the semantics of the private keyword in this case
    You could have done a better job with keeping to the Liskov substitution principle. Public inheritance means "is-a", thus an attempt to make private an override of a public member function is a design flaw in your own code.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The real question is, why doesn't the compiler complain the moment you override a function with one that has lesser access?

    I know I saw a rationale for that once, but I can't remember where or what it was.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    I think its more of a design flaw on your behalf than on the language's behalf. You could use this sort of thing for encapsulation, though you would be utilizing it in the exact reverse of how you just did things here. Though anyone who has access to the original base object, theoretically always can gain access to any subsequent derivation of that class. So I don't think there is much logical reason to try using it in a positive way. At least nothing overly contrived that I can work up now (hense my lack of an example).

  7. #7
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    Quote Originally Posted by CornedBee View Post
    The real question is, why doesn't the compiler complain the moment you override a function with one that has lesser access?

    I know I saw a rationale for that once, but I can't remember where or what it was.
    I was thinking exactly the same. Aside from the contrived example I gave (which may or may not be paradigm-correct), I can see a scenario occuring in which someone derives from some public API base class, forgets about some obscure inherited virtual they never intend to use and accidentally declares a private function of the same name. In which case it would be beneficial to issue a warning to the effect of
    warning: private member function foo overloads public virtual function bar of class Fred - private access modifier will be ignored

  8. #8
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    I thought this type of override does throw a warning on all the major compilers.

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by master5001 View Post
    I thought this type of override does throw a warning on all the major compilers.
    g++ (MinGW's g++, anyway), using -Wall and -Wextra, says this:
    Code:
    
    

  10. #10
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    For shame, g++! Even with pedantic flags? Bleh this machine doesn't have any compilers on it.

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    To be fair, Visual Studio 2008 C++ says this:
    Code:
    
    
    Those are all the compilers I can get to.

  12. #12
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    I don't think you can get any more common-place than VC++ and gcc. I mean I could break out a Borland one but I really couldn't care less what faults that one finds in anything.

  13. #13
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Private, public and protected and any mechanismsin C++ that are made in order to deny access to memory that was not intended to be accessed by the accessor(Lawl), are purely language semantics. If you were to compile an executable that initializes a class with a public variable and private variable, initializes both and prints the public one, and then run it through a debugger and swap out the address of the public variable that's being accessed in your print function, with the private variable's address, nothing would happen.

    The memory isn't protected. AFAIK, there is no such mechanism in (at least) windows, except to change Read/Write/Copy privileges and so on. AFAIK, you cannot prohibit a process to access its own memory due to the current context of the running code.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  14. #14
    Registered Abuser
    Join Date
    Jun 2006
    Location
    Toronto
    Posts
    591
    That's understood (in fact, the same could be done for "const"ness).
    Instead, we're discussing what happens at compile time, when overloading a public virtual with a private changes the normal semantics of the "private" keyword.
    Actually, I was just going to draw analogy to "const", but looks like this suffers from similar problems:
    Code:
    class EventHandler
    {
      public: virtual void handleEvent( ) { d++; }
      int d;
    };
    
    class MyEventHandler : public EventHandler
    {
     // woops! there goes the "const"ness
     // so much for empty promises
      private: void handleEvent( ) const { (void)e; }
      int e;
    };
    
    void handleEvents( EventHandler *eh )
    {
      eh->handleEvent( );
    }
    
    int main()
    {
      MyEventHandler meh;
      handleEvents( &meh );
    }
    Surprisingly, "const"ness is violated here and still no warning is generated! These are the kinds of things I'd expect a compiler to flag (all the necessary information is present at compile time). The fact that private and const semantics can change so discreetly does seem a bit of a design flaw...

  15. #15
    Registered User
    Join Date
    Jan 2007
    Posts
    330
    Quote Originally Posted by @nthony View Post
    That's understood (in fact, the same could be done for "const"ness).
    Instead, we're discussing what happens at compile time, when overloading a public virtual with a private changes the normal semantics of the "private" keyword.
    Actually, I was just going to draw analogy to "const", but looks like this suffers from similar problems:
    Code:
    class EventHandler
    {
      public: virtual void handleEvent( ) { d++; }
      int d;
    };
    
    class MyEventHandler : public EventHandler
    {
     // woops! there goes the "const"ness
     // so much for empty promises
      private: void handleEvent( ) const { (void)e; }
      int e;
    };
    
    void handleEvents( EventHandler *eh )
    {
      eh->handleEvent( );
    }
    
    int main()
    {
      MyEventHandler meh;
      handleEvents( &meh );
    }
    Surprisingly, "const"ness is violated here and still no warning is generated! These are the kinds of things I'd expect a compiler to flag (all the necessary information is present at compile time). The fact that private and const semantics can change so discreetly does seem a bit of a design flaw...
    Nothing surprising here. The const version does not override the one in the baseclass so when you have a EventHandler * the one in the baseclass gets called. If you want the const version you'll have to cast it.

    Code:
    ((MyEventHandler *)handle)->handleEvent();
    Only then the const version is called

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Implementing Inheritence into your design
    By bobthebullet990 in forum C++ Programming
    Replies: 6
    Last Post: 08-05-2006, 04:40 PM
  2. Cprog tutorial: Design Patterns
    By maes in forum C++ Programming
    Replies: 7
    Last Post: 10-11-2004, 01:41 AM
  3. linked list of templates (or a design flaw?)
    By Ess in forum C++ Programming
    Replies: 3
    Last Post: 11-30-2002, 08:15 PM
  4. is this a design flaw
    By blight2c in forum C++ Programming
    Replies: 5
    Last Post: 03-20-2002, 12:33 AM