Assume you have a class that defines virtual methods with the access specifier public.
Can you change the access specifier on your overriden methods?
I am assuming no.
Looking for an explanation.
The answer is: sort of. You can only change the access of members the derived class has access to. The type of inheritance has no effect - this only controls the default access for inherited members (to a point, following other rules).
So, you can make a base class's protected members public or private; or a base's public members protected or private. You cannot, however, make a base's private members public or protected.
Example:
class Foo
{
protected:
void protected_member();
private:
void private_member();
public:
void public_member();
};
class Bar : private Foo
{
public:
using Foo::protected_member;
using Foo::private_member;
using Foo::public_member;
};
int main(int, const char**)
{
Bar bar;
return 0;
}
The above code elicits the following error on g++ 4.1.2:
main.C:7: error: 'void Foo::private_member()' is private
main.C:14: error: within this context
Additionally, overriding has nothing to do with changing the access of a method. You can override a virtual private method, you just cannot call it from a derived class.
Yes you can, but it "doesn't grok".
Take a look at Overriding public virtual functions with private functions in C++
You definitely can. But it makes no sense. If it is a public inheritance, then you can always cast an object to its base. If it's a private inheritance, all base methods are already private by default. In case of protected inheritance you can make the base method private, so you prevent possible derived classes from calling it, but I don't really understand why one might need it.
Yes you can, and in fact you don't even need to override or use virtual anything.
class ABC {
public: // or this may be protected, no difference
void woof();
void moo();
};
class D : private ABC { // now woof and moo are private
public:
using ABC::woof; // using declaration to make woof public again
ABC::moo; // access declaration (deprecated) does the same
};
The same works if they are virtual, too. Or, as others noted, virtual function lookup ignores the access specified by the implementing class; any class you can cast to may provide access at compile time.
On the other hand, without the special declarations in D, the public interface of ABC would indeed be inaccessible through D because you wouldn't be able to upcast to ABC. And if woof and moo were virtual, you would want to make the overrides private to hide them. Perhaps that better answers the question.
Related
Consider the following snippet:
struct Base
{
virtual ~Base() {}
virtual void Foo() const = 0; // Public
};
class Child : public Base
{
virtual void Foo() const {} // Private
};
int main()
{
Child child;
child.Foo(); // Won't work. Foo is private in this context.
static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context.
}
Is this legal C++? "This" being changing the virtual function's access mode in the derived class.
This is legal C++, §11.6/1 says:
Access is checked at the call point
using the type of the expression used
to denote the object for which the
member function is called (B* in the
example above). The access of the
member function in the class in which
it was defined (D in the example
above) is in general not known.
As you noted, Child::Foo() is thus still accessible via the base class, which is in most cases undesired:
Child* c = new Child;
Base* b = c;
c->Foo(); // doesn't work, Child::Foo() is private
b->Foo(); // works, calls Child::Foo()
Basically, the declaration you refer to in the expression dictates the access mode - but virtual functions undermine that as another function then the named one may actually be invoked.
Yes, changing the access mode in derived classes is legal.
This is similar in form but different in intent to the Non-Virtual Interface idiom. Some rationale is given here:
The point is that virtual functions exist to allow customization; unless they also need to be invoked directly from within derived classes' code, there's no need to ever make them anything but private.
As to why you would actually make something public in base but private in derived without private or protected inheritance is beyond me.
It is perfectly legal C++. You are simply defining a new method in Child class.
Now does it do what you want it to do, that's an other question.
I believe the access mode is not part of the method signature, which means that calling Base's Foo virtual method does eventually call Child's Foo method.
So here's the conclusion : it is legal c++ and it works the way you'd expect.
I am not taking into consideration the line child.Foo(); which can't work because there is no doubt it is trying to access Child's private Foo() method.
It seems to compile and call the right method.
Remember that access specifiers are there to help a disciplined programmer, not to prevent all attempts to circumvent it at all costs.
In this particular case, Child has no business making the overridden virtual function private: isn't it supposed to implement the public interface of Base, so the "is-a" relationship holds? (If you didn't use public inheritance, which means "Child is a Base", your trick wouldn't work.)
I have an abstract class base with private member variable base_var. I want to create a derived class, which also has base_var as a private member.
To me, this seems like an obvious thing you would want to do. base is abstract so it will never be instantiated. The only time I will create a base-object is if it is actually a derived object, so obviously when I give ´base´ a private member variable, what I am really trying to do is give that variable to all of its derived objects.
However, the below diagram seems to suggest that this is not doable with inheritance?
Why not? What would then even be the point of having private stuff in an abstract class? That class will never be instantiated, so all that private stuff is essentially useless?
However, the below diagram seems to suggest that this is not doable with inheritance?
Correct, private members of a class can not be accessed by derived classes. If You want a member of a class to be accessible by its derived classes but not by the outside, then You have to make it protected.
Why not? What would then even be the point of having private stuff in an abstract class? That class will never be instantiated, so all that private stuff is essentially useless?
Even an abstract class can have member functions which act on a (private) member variable. Consider (somewhat silly example, but well):
class MaxCached
{
private:
int cache = std::numeric_limits<int>::min();
public:
bool put(int value)
{
if (value > cache)
{
cache = value;
return true;
}
return false;
}
int get() const
{
return cache;
}
virtual void someInterface() const = 0;
};
Deriving from this class gives You the functionality of the base class (put and get) without the danger of breaking it (by for example writing a wrong value to cache).
Side note: Above is a purely made up example! You shouldn't add such a cache (which is independent of Your interface) into the abstract base class. As it stands the example breaks with the "Single Responsibility Principle"!
Just because a class is abstract doesn't mean there cannot be code implemented in that class that might access that variable. When you declare an item in a class to be private, the compiler assumes you had a good reason and will not change the access just because it there is a pure virtual function in the class.
If you want your derived classes to have access to a base class member declare the member as protected.
I have an abstract class base with private member variable base_var
class foo {
public:
virtual void a_pure_virtual_method() = 0;
int get_var() { base_var; }
virtual ~foo(){}
private:
int base_var;
};
Note that a class is said to be abstract when it has at least one pure virtual (aka abstract) method. There is nothing that forbids an abstract class to have non-pure virtual or even non-virtual methods.
I want to create a derived class, which also has base_var as a private member.
class derived : public foo {};
To me, this seems like an obvious thing you would want to do.
Sure, no problem so far.
The only time I will create a base-object is if it is actually a derived object, so obviously when I give ´base´ a private member variable, what I am really trying to do is give that variable to all of its derived objects.
Still fine.
Why not?
You are confusing access rights that are display in the image you included with the mere presence of the members in the derived. The derived class has no access to members that are private in the base class. Period. This is just according to the definition of what is private.
What would then even be the point of having private stuff in an abstract class? That class will never be instantiated, so all that private stuff is essentially useless?
It is not useless at all. Derived classes inherit all members, they just cannot access all of them. The private stuff is there you just cannot access it directly. Thats the whole point of encapsulation. Consider this example:
class bar : public foo {
void test() {
std::cout << base_var; // error base_var is private in foo
std::cout << get_var(); // fine
}
};
Why does this happen?
http://coliru.stacked-crooked.com/a/e1376beff0c157a1
class Base{
private:
virtual void do_run() = 0;
public:
void run(){
do_run();
}
};
class A : public Base {
public:
// uplift ??
virtual void do_run() override {}
};
int main()
{
A a;
a.do_run();
}
Why can I override a PRIVATE virtual method as public?
According to https://en.cppreference.com/w/cpp/language/virtual#In_detail overriding a base's virtual member function only care about the function name, parameters, const/volatile-ness and ref qualifier. It doesn't care about return type, access modifier or other things you might expect it to care about.
The linked reference also specifically notes that :
Base::vf does not need to be visible (can be declared private, or inherited using private inheritance) to be overridden.
Nothing that I can find explicitly gives permission to do this, but the rules of overriding do not prevent it. It's allowed by virtue of virtual functions and function overriding existing and not disallowing this case.
If you are asking why this is how the language is, you may have to ask the standardization committee.
That behavior is intended. If a method is virtual then it's meant to be customizable by derived classes, regardless of access modifier.
See here
Why I can override PRIVATE virtual method as public???
Because you look at the base method being private at wrong angle. B::do_run being private means "only members and friends of this class can use it". To prohibit derived classes from overriding it we would need separate specifier but we can simply make it not virtual. Class A on another side allows anybody to call A::do_run() and it is up to class A designer to decide so. So there is no uplift as you see it.
Notice that this implementation does not change the way how the base class is accessed and a construct:
Base& b = a;
b.do_run();
will not work.
I remember there is some rationale behind it described in more detail in "Effective C++" by Scott Meyers. But the key practical feature is to be able to use such flexibility in the opposite direction, to override public base class members with private functions in a derived class forcing the client to use the base class as the interface and not be tempted to use directly the derived one that should remain a hidden implementation.
If the intention is to write a private code for the base-class & to prevent the possibility of override it, implement the private function in the base class, and declare it final, otherwise: When should someone use private virtuals? ISOCPP.ORG FAQ
Given that we have overloaded methods in base class, and a derived class that was inherited as private/protected.
Can we restore only one/several of the original access level of the overloaded methods?
On GCC 4.4.0 i try to put the base methods under protected access, then inherited it using private access. When i try to restore the access level to public, it works! Is this how its suppose to work? or is it a bug on the compiler? To my understanding, restoring access level shouldn't be able to be used to promote or demote a member's access level.
Code snippet :
class base {
public:
void method() {}
void method(int x) {}
protected:
void method2() {}
};
class derived : private base {
public:
base::method; // Here, i want to restore only the none parameterized method
base::method2; // method2 is now public??
};
Changing accessibility of inherited functions through a using declaration cannot be done selectively on given overload for the simple reason that a using declaration only introduces a name into the declarative region and that by definition, functions overloads share the same name.
The only alternative I see here is to use trivial forwarding functions :
class derived : private base
{
public:
void method() { base::method(); }
using base::method2; // method2 is now public
// method(int) stays inaccessible
};
I'm not quite sure I understand your second question, but yes : you can change base members accessibility in a derived class through using declarations.
You don't restore access, per se. You set access. As you are doing above, you can explicitly set the access for any method, including ones previously declared as private.
It would be impossible to prevent protected methods from being public if the derived class wanted it so, as you could just write a minor wrapper and done. private is another matter.
What are the rules for accessibility when virtual functions are declared under 3 different access specifiers specified by C++(public, private, protected)
What is the significance of each? Any simple code examples to explain the concept will be highly useful.
Access specifiers apply in the same way as they would to any other name during name lookup. The fact that the function is virtual does not matter at all.
There is a common mistake which sometimes happens with respect to virtual functions.
If name lookup determines a viable function to be a virtual function, the access specifier of the virtual function is checked in the scope of the static type of the object expression used to name the function. At run time, the actual function to be called could be defined in the derived class with a completely different access specifier. This is because 'access specifiers' are a compile time phenomonon.
// Brain compiled code ahead
struct A{
virtual void f() {}
private:
virtual void g() {}
protected:
virtual void h() {}
};
struct B : A{
private:
virtual void f() {} // Allowed, but not a good habit I guess!
};
B b;
A &ra = b;
ra.f(); // name lookup of 'f' is done in 'A' and found to be public. Compilation
// succeeds and the call is dynamically bound
// At run time the actual function to be called is 'B::f' which could be private, protected etc but that does not matter
Virtual functions are just like regular functions (exception of pure virtuals) when they are used in the base class.
To summarise from the top of my head:
public functions can be accessed by anyone.
private functions can be accessed only be the class and its friends
protected functions are like private ones, only they can be accessed by derived classes.
Public is the interface, and private/protected functions are the internals.
Also note that all the local variables (according to encapsulism) should be protected/private.
Now, when it comes to derived classes, you derive a class like this:
class A : [public | protected | private] B
{
};
Now, the public/private/protected qualifier infront of B states the least restrictive security level to inherit from the base class. This is not a "filter" for the methods and local variables in the sense that some aren't inherited, it just changes their security level to the one specified if they are less restricted (more public).
So class A : public B will leave the inherited base members as they are while,
class A : private B will change them all to private members.
Hope this makes sense to you and answers your question. If not, tell me!