I'm confused as to why the C++ compiler won't accept this:
class Foo {
private: void Baz() { }
};
class Bar {
public: void Baz() {
};
class FooBar : public Foo, public Bar { };
void main() {
FooBar fb;
fb.Baz();
}
The error gcc gives is:
request for member ‘Baz’ is ambiguous
candidates are: void Bar::Baz()
void Foo::Baz()
but isn't it obvious that I want Bar::Baz(), since Foo::Baz() is private? Why won't the compiler disambiguate here?
Name resolution works in two stages. First the name is looked up then the name is checked for access. If the name look up is ambiguous then the access is never considered.
As to why, maybe it's a deliberate language design, but I think more likely it's just to simplify the process of resolving names. The rules are fiendishly complicated already.
It's not obvious - you might have wanted to call the private member (if that was possible).
Formally, the language rules say that the name is resolved first and the best overload is selected. Only after that is there a check for accessibility.
In order to allow this, it would need to consider whether or not you are in a context that allows you to call a private method or not. If this were allowed then the call:
fb.Baz()
could have completely different functionality depending on whether you were calling it from a public or private context. And that's not really inline with the way the language works.
As others have said, first the name is looked up, then access restrictions are applied. You can work around this by explicitly calling the method you wish, as in
fb.Bar::Baz()
Access restrictions don't affect inheritance. You always inherit everything from all base classes. In your case that may seem unnecessary, but consider a slightly modified version where the private function is virtual:
class Base
{
virtual void secret_power() { /* innocent default */ }
public:
void use_me() { secret_power(); }
};
class Derived : public Base
{
virtual void secret_power() { /* overriding implementation here */ }
};
Now for any Base& you can always call the non-virtual public interface use_me(), but your derived classes provide the implementation by means of a private virtual.
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 a situation where I am using a public API and need to "override" a function in a parent class, however this function has not been declared as virtual. Although it is hacky, I have decided that I am going to change the visibility of the parent class function using the code mentioned here: a way in c++ to hide a specific function.
I am, however, facing an issue, in that the parent class has an overload of this function with very similar parameters, and I am therefore getting the error "ambiguous call to overloaded function", even though I have made the parent class's function's scope private in my child class. I have simplified the solution below to illustrate the problem:
class Parent
{
public:
void doSomething(void* pointer) {}
};
class Child : public Parent
{
public:
void doSomething(const char* pointer) {}
private:
using Parent::doSomething;
};
int main()
{
Child childInstance;
childInstance.doSomething(nullptr); // error: 'Parent::doSomething': ambiguous call to overloaded function
}
Is this a bug? If not, how do I get around this? I am confused as to why the compiler is even searching in the parent class's namespace, when I have explicitly declared doSomething() as private?
I am using MSVC 2019.
I do NOT want to do either of the following:
Rename my subclass function (as this will cause inconsistency for me)
Make my inheritance private and manually make public the functions I need (as the inheritance tree is extremely big and this would require making numerous functions in grandparent classes public too and so on, which is unsustainable)
The simplest approach is just not to have the using directive in the first place.
The inherited function is already hidden because you have a function with the same name. The using directive explicitly un-hides that overload, which actually creates the problem you are trying to solve.
class Child : public Parent
{
public:
void doSomething(const char* pointer) {}
};
With this definition of Child, the inherited void doSomething(void*); overload is hidden. Even Child foo; foo.doSomething(static_cast<void*>(nullptr)); won't compile!
If you need to call the version on Parent from within Child, you can just qualify the invocation: Parent::doSomething(arg);.
Assuming your problem is specific to nullptr, you could also declare an additional overload that takes std::nullptr_t, which is always the best match for nullptr:
class Child : public Parent
{
public:
void doSomething(const char* pointer) {}
void doSomething(std::nullptr_t) {
doSomething(static_cast<const char*>(nullptr));
}
private:
using Parent::doSomething;
};
Is this a bug? I am confused as to why the compiler is even searching in the parent class's namespace
The compiler doesn't have to look in the parent class. You explicity told him that you want to use Parent::doSomething;.
Moreover, overload resolution happens before private/public access (cf cppreference):
Member access does not affect visibility: names of private and privately-inherited members are visible and considered by overload resolution, implicit conversions to inaccessible base classes are still considered, etc. Member access check is the last step after any given language construct is interpreted. The intent of this rule is that replacing any private with public never alters the behavior of the program.
Both overloads are an equally good match, hence the ambiguity. Passing a void* should be fine to select the desired overload:
childInstance.doSomething(static_cast<void*>(nullptr));
To have the method from Parent hidden as private and resolve the ambiguity you can add a level of indirection:
class Parent
{
public:
void doSomething(void* pointer) {}
};
class Intermediate : public Parent {
using Parent::doSomething;
};
class Child : public Intermediate
{
public:
void doSomething(const char* pointer) {}
};
int main()
{
Child childInstance;
void* p;
//childInstance.doSomething(p); // error
childInstance.doSomething(nullptr); // fine
}
The intermediate ensures that Parent::doSoemthing is private and the call is no longer ambiguous.
Say you are given the following UML class diagram:
Can a variable of type Mystery invoke the function DoSomething()?
I understand that an object (say Mystery X;) could call GetA() to access the private variable int a
and to access the public variable int b all you need is X.b
but how could this object, X, access the private function DoSomething()
if it's even possible?
I had difficulty understanding exactly what you are asking, but I think I've figured it out.
If you are asking if, given the following declaration:
class Mystery
{
/*...*/
private:
void DoSomething();
};
you can do something like this:
Mystery m;
m.DoSomething();
...then the answer is no. You cannot call private member functions (or refer to private member variables) from outside the context of the class. Only another member function of Mystery can call the privates. For example:
void Mystery::Foo()
{
DoSomething(); // this would be possible if Foo() is a member of Mystery
}
EDIT:
Not only can you not call private members from outside the class, you also can't call them from subclasses. For example, this is not valid:
class Base
{
private:
void Foo() {};
};
class Child : public Base
{
public:
void Bar()
{
Foo(); // ERROR: Can't call private method of base class
}
};
There is one (edit - for completeness sake, there is more than one, see the comments) weird way that a private member function could be called outside your class, but it requires a little bit of a contrived example, where you can return a pointer to this function:
class Mystery;
typedef void (Mystery::*fptr)();
class Mystery{
void DoSomething() {};
public:
static fptr GetPrivateDoSomething()
{
return &DoSomething;
}
};
int main(int argc, char *argv[])
{
Mystery m;
fptr ds = Mystery::GetPrivateDoSomething();
(m.*ds)();
return 0;
}
That being said, don't do this. Private methods are private for a reason - they embody hidden aspects of the design, and were never meant to be a part of the exposed interface. That means that they could be subject to a change in behavior, or even complete removal. Additionally, doing these sorts of shenanigans can lead to code that is highly and awkwardly coupled, which is undesirable.
THAT being said, I have indeed used this and it works quite well, although it was in an entirely different context where it helped to reduce coupling (it was in a highly-modular event registration scheme, if you were wondering).
Any method inside the class is allowed to access the private variables and methods. It works exactly like calling any other method, its just that the compiler will give you an error if you try to do it from outside the class.
I'm confused as to why the C++ compiler won't accept this:
class Foo {
private: void Baz() { }
};
class Bar {
public: void Baz() {
};
class FooBar : public Foo, public Bar { };
void main() {
FooBar fb;
fb.Baz();
}
The error gcc gives is:
request for member ‘Baz’ is ambiguous
candidates are: void Bar::Baz()
void Foo::Baz()
but isn't it obvious that I want Bar::Baz(), since Foo::Baz() is private? Why won't the compiler disambiguate here?
Name resolution works in two stages. First the name is looked up then the name is checked for access. If the name look up is ambiguous then the access is never considered.
As to why, maybe it's a deliberate language design, but I think more likely it's just to simplify the process of resolving names. The rules are fiendishly complicated already.
It's not obvious - you might have wanted to call the private member (if that was possible).
Formally, the language rules say that the name is resolved first and the best overload is selected. Only after that is there a check for accessibility.
In order to allow this, it would need to consider whether or not you are in a context that allows you to call a private method or not. If this were allowed then the call:
fb.Baz()
could have completely different functionality depending on whether you were calling it from a public or private context. And that's not really inline with the way the language works.
As others have said, first the name is looked up, then access restrictions are applied. You can work around this by explicitly calling the method you wish, as in
fb.Bar::Baz()
Access restrictions don't affect inheritance. You always inherit everything from all base classes. In your case that may seem unnecessary, but consider a slightly modified version where the private function is virtual:
class Base
{
virtual void secret_power() { /* innocent default */ }
public:
void use_me() { secret_power(); }
};
class Derived : public Base
{
virtual void secret_power() { /* overriding implementation here */ }
};
Now for any Base& you can always call the non-virtual public interface use_me(), but your derived classes provide the implementation by means of a private virtual.
Is there any issue with partially overriding a set of virtual functions defined by a base class?
My compiler provides the following warning:
overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass".
The classes look like this:
class MyBaseClass
{
public:
virtual void setValue(int);
virtual void setValue(SpecialType*);
}
class MyDerivedClass : public MyBaseClass
{
public:
virtual void setValue(int);
}
The easy way to get rid of this warning is to use different names for the base functions, but I wanted to know if there was any compelling reason to fix this specific warning. I do not believe this violates the C++ standard. My guess is that it's to warn a programmer that they may have forgotten to implement the behavior for all possible input types. In our case, it is intentional to exclude some of the specific types.
Would you discourage suppressing this warning altogether?
The override for setValue(int) hides setValue(SpecialType*) of the base class (see the C++ FAQ Lite), so if you try to call setValue(new SpecialType()) you will get an error.
You can avoid this by adding a using directive to the derived class that "imports" the overloads from the base class:
class MyDerivedClass : public MyBaseClass
{
public:
using MyBaseClass::setValue;
virtual void setValue(int);
};
The warning is correct, it's called "name hiding". A variable of type MyDerivedClass cannot call setValue(SpecialType*).
Now I'm going to blatantly rip off someone else's blog:
Overloading and name hiding in C++
In a phone conversation with Brad last night, he told me about a strange problem he's encountered in his new C++ job. Granted, it's probably no big deal to people with extensive C++ experience, but to those of us who live in managed code worlds, this seemed strange.
In C++, when you have a class with an overloaded method (member function, whatever you want to call it), and you then extend and override that method, you must override all of the overloaded methods.
I understand the case where you have changed a method signature in a child class, thereby invalidating the established interface. In this case, though, it seems counterintuitive, since you're not changing the interface, but selectively overriding. Which is different.
For example:
class FirstClass
{
public:
virtual void MethodA (int);
virtual void MethodA (int, int);
};
void FirstClass::MethodA (int i)
{
std::cout << "ONE!!\n";
}
void FirstClass::MethodA (int i, int j)
{
std::cout << "TWO!!\n";
}
Simple class here with two methods (or one overloaded method). You want to override the two-parameter version, so you continue with the following:
class SecondClass : public FirstClass
{
public:
void MethodA (int);
};
void SecondClass::MethodA (int i)
{
std::cout << "THREE!!\n";
}
Now, when you use an instance of SecondClass, most Java or C# programmers might assume you can call:
int main ()
{
SecondClass a;
a.MethodA (1);
a.MethodA (1, 1);
}
However, the second call won't work, since the two-parameter MethodA is not visible. You can get a pointer and up-cast to FirstClass, but your SecondClass instance doesn't inherit the non-overridden methods directly.
It's clear that the compiler wants to warn you: you created a subclass that behaves differently when giving it an int, but you didn't change it's behavior when giving it a SpecialType*.
Although this might be the intention, it is very very possible that the changed behavior is also needed for the other overloaded virtual functions.
I wish the compiler had warned me harder, the time I ignored it! My overridden method turned out to compile and work well in my scenario, but some other scenario's went really wrong due to the overload not being overridden.
Think twice before you disable that warning!
If you want the original behavior kept, it's easy to just call the parent function:
class MyDerivedClass : public MyBaseClass {
virtual void setValue(int);
// explicit: keep original behavior for SpecialType
virtual void setValue( SpecialType* p ) { MyBaseClass::setValue(p); }
};