6

I ended up coding (With some help) something like this yesterday:

#include <iostream>

using namespace std;

class A
{
    public:
        virtual void foo(){cout << "A::foo\n";}
};

class B : private A
{
    private:
        virtual void foo(){ cout << "B::foo\n";}
        void DoSomething(SomeOtherClass& o){o.DoSomething(*static_cast<A*>(this));}
};

I tried changing the inheritance method:

class B : public A
{
    private:
        virtual void foo(){ cout << "B::foo\n";}
};

int main()
{
    A* a = new B;
    a->foo();
}

This still works. I expected a compile time error. Please tell me why this is possible and what are the possible uses? I know one use due to first scenario - You can expose different interfaces for different classes.

EDIT:

In the second case, output is B::foo.

nakiya
  • 14,063
  • 21
  • 79
  • 118
  • Where did you expect the error? On the declaration of the function as private? Or on the calling of the function? – Benjamin Lindley Nov 04 '10 at 07:41
  • 1
    I'm intrigued. Hoping for an answer that would explain the possible usages of this feature (?). One usage might be to force the programmer to instantiate the class B as a pointer to base class A in order to use it's interface. But why that would be A Good Thing, I don't know. – manneorama Nov 04 '10 at 08:19
  • @PigBen: I expected the error at the definition of `foo` in `B` in the second case. – nakiya Nov 04 '10 at 08:49
  • @manneorama: Check this problem I posted yesterday. It is from it that I got this one :). http://stackoverflow.com/questions/4084772/how-to-expose-a-subset-of-the-public-interface-to-a-class – nakiya Nov 04 '10 at 08:50
  • Possible duplicate of [c++ using declaration, scope and access control](http://stackoverflow.com/questions/2084801/c-using-declaration-scope-and-access-control) – underscore_d Aug 16 '16 at 21:42

2 Answers2

3
using namespace std; 

class A 
{ 
    public: 
        virtual void foo(){cout << "A::foo\n";} 
}; 

class B : public A 
{ 
    private: 
        virtual void foo(){ cout << "B::foo\n";} 
}; 

int main() 
{ 
    A* a = new B; 
    a->foo(); 
} 

This works because at compile time the compiler can only see that a is a pointer to the base class A and foo() is a public method being called on a, which is perfectly valid. The virtual binding happens dynamically at run time after the compilation, this virtaul binding decides that the actual call is to B::foo() and not A::foo() that is the the performance penalty of using virtualism.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • It's easy to see why it works. But it would have made a lot more sense if it was not allowed to make foo() private in B. So I think the question is, what is the rationale behind that design decision. – Johan Kotlinski Nov 04 '10 at 07:59
  • @kotlinski: There is a very famous design pattern called "Template method" pattern which makes use of this rationale. Please check that. – Alok Save Nov 04 '10 at 08:18
  • 1
    I don't see the connection between this and the template method design pattern. – nakiya Nov 04 '10 at 09:07
  • Template method pattern uses private both in base and derived class. That makes sense. Changing access from public to private in this case just seems confusing. Private just doesn't mean anything useful - it's still possible to call the supposedly "private" function by going through the base class. – Johan Kotlinski Nov 04 '10 at 10:31
1

May not answer all your questions directly, nevertheless I decided to put it up here for future reference. Also please take it with a pinch of salt as this is based on my understanding of the events that have happened in the C++ Standard world, rather than the actuals.

Read this. I don't have the ARM with me, but the article gives necessary details.

Note 115 in C++0x says

115) Access declarations are deprecated; member using-declarations (7.3.3) provide a better means of doing the same things. In earlier versions of the C++ language, access declarations were more limited; they were generalized and made equivalent to using-declarations in the interest of simplicity. Programmers are encouraged to use using-declarations, rather than the new capabilities of access declarations, in new code.

In summary:

I think the ARM prohibited it initially:

An access declaration may not be used to restrict access to a member that is accessible in the base class, nor may it be used to enable access to a member that is not accessible in the base class.

But later on I guess when the Standard evolved this was eventually allowed

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • "eventually allowed" well, now, they're deprecated. this answer had a better quote: http://stackoverflow.com/questions/2084801/c-using-declaration-scope-and-access-control – underscore_d Aug 16 '16 at 21:42