This code
struct Foo{
void f(){
f(0);
}
private:
void f(int){}
};
struct Bar : private Foo{
using Foo::f;
};
int main() {
Bar b;
b.f();
}
fails to compile because Foo::f(int) is private. I am not interested in Foo::f(int), I just want Foo::f() which is public, so I feel there should be a way to do it.
There are some workarounds I can think of:
rename Foo::f(int) to Foo::p_f(int), but that is redundant and disallows overload resolution for f
implementing Bar::foo(){Foo::f();} becomes a lot of copy/paste for multiple public fs
inheriting publicly from Foo which invites UB since ~Foo() is not virtual (and is not supposed to be)
making all fs public makes it too easy to accidentally break Foo and Bar
Is there a way to say using public Foo::f;? Or use one of the workarounds without the associated downsides?
If your f(int) is supposed to be private, and will never ever be part of a public API, then you should not care about renaming it to fimpl:
struct Foo{
void f(){
fimpl(0);
}
private:
void fimpl(int){}
};
If, on the other hand, f(int) is the general version of a public API, and you also want a single convenience wrapper with a particular value, you can use provide a default argument and make f(int) a public member.
struct Foo{
void f(int = 0){}
};
Finally, if you want several named functions that provide certain integer values, then I'd suggest renaming those wrappers
struct Foo{
void f(int) {} // general interface
void sensible_name1() { f(0); }
void sensible_name2() { f(1); } // etc.
}
Your code currently derives Bar from Foo as private. Due to that, Foo::f() is a private method in Bar. You can change that by changing your class declaration to struct Bar: public Foo.
For some background, see the Section on "Private Inheritance" under Derived Classes. Specifically, the section explains that:
[w]hen a class uses private member access specifier to derive from a base, all public and protected members of the base class are accessible as private members of the derived class (private members of the base are never accessible unless friended).
Related
Let's say I have a nice looking base class called base:
class base
{
public:
virtual void foo() const = 0;
};
Now, I have a class named foo that I would like to inherit from base and override base::foo:
class foo : public base
{
public:
virtual void foo() const override;
};
This is illegal in C++, as you are not allowed to name a method the same thing as the class (C++ greedily believes methods with the same name as the class are constructors, which are not allowed to have return types). Is there any way around this that doesn't involve changing the name of the class or method? I want external users to be able to create foo classes without the knowledge that there is a method base::foo called by someone else (imagine foo can be both a noun and a verb).
Is there any way around this that doesn't involve changing the name of the class or method?
No, there isn't.
All methods named foo are special in class foo -- they are constructors. Hence, they cannot be overridden virtual member functions.
I'll take a wild guess and just say NO.
You can have a lot of ambiguities in C++ (that sometimes have to be explicitly disambiguated), but I don't even see a way how a compiler or programmer could disambiguate this situation. Well, A programmer can (a function with a return type is obviously not a constructor), but C++ can't.
In C++, the only method that can have the class' name is its constructor.
So, no. You can't.
Okay, here's my (slightly evil) solution...
// Create an intermediate class which actually implements the foo method:
class foo_intermediate : public base
{
public:
virtual void foo() const override;
};
// Derive from that class and forward the constructor along
class foo : public foo_intermediate
{
public:
using foo_intermediate::foo_intermediate;
private:
friend class foo_intermediate;
// Actual implementation for the foo function goes here
void foo_impl() const;
};
// In some CPP file:
void foo_intermediate::foo() const
{
// Need to access the typename foo via namespace (global here)
static_cast<const ::foo*>(this)->foo_impl();
}
Actually calling foo is a bit funny, since this can't work:
void bar()
{
foo x;
x.foo(); // <- illegal attempt to access to the foo constructor
}
You must access through an alias:
void baz()
{
foo x;
base& rx = x;
rx.foo(); // legal
}
As an alternative, you can use a typedef:
class foo_impl : public base
{
public:
virtual void foo() const override;
};
using foo = foo_impl;
This gets around the issue of calling x.foo(), since it no longer appears as a constructor access.
I made a Gist so others could play with the two solutions if they are so inclined.
I'm new to C++, and I'm familiar with Java. The first thing I was wondering about when I started looking at C++ code is that classes themselves (not the members) don't have access specifiers such private, protected and public. Exemples here and here.
public class A { // This line.
private class B { } // Not this line.
}
Why is that so?
There's no access modifier at the level of classes, since the language has no concept of package. But there is at the level of data members, member functions and inheritence:
class Foo {};
class Bar : public Foo {
public:
void bar() const {}
private:
int bar_(float) {}
int a, b, c;
};
The closest you can get is declaring nested classes inside a class:
class Foo {
struct Bar0 {
void bar0() const {}
};
struct Bar1 {
Bar0 b0;
Bar1() { b0.bar0();}
};
};
There's no need for class-level access specifier. If you want a private class, you can define it in an implementation file or an anonymous namespace. This sort of restriction is done at file-level for C++ (i.e. how you organize your headers, preprocessor directives).
Before edit:
They do, but they're not per-method. Also, classes have a default private specifier, so, unless otherwise noted, they are private.
class A
{
void foo(); //private
};
class B
{
void foo(); //private
public:
void foo1(); //public
void foo2(); //public
protected:
void foo3(); //protected
private:
void foo4(); //private
};
Note 1 C++ also has struct, which is identical to a class except the default access level is public.
Note 2 There is no package-scope in C++. In Java, protected gives access to the whole package, in C++ it just gives access to deriving classes.
Note 3 The friend keyword can be used to bypass restrictions, look it up.
C++ uses a slightly different syntax where access modifiers are specified for groups of declarations instead of individually:
class Test {
class MyPrivateClass {
// ...
};
void privateByDefault();
public:
void myPublicFunction();
void anotherPublicFunction();
private:
void myPrivateFunction();
public:
class MyPublicClass {
// ...
};
void morePublicFunctions();
protected:
// ...
};
Test::MyPrivateClass is inaccessible outside of Test, while Test::MyPublicClass can be used anywhere.
From your source: http://www.cplusplus.com/doc/tutorial/classes
private members of a class are accessible only from within other
members of the same class or from their friends. protected members are
accessible from members of their same class and from their friends,
but also from members of their derived classes. Finally, public
members are accessible from anywhere where the object is visible.
i have an inheritance struct A : public B, i want to hide individual functions from B, is this possible?
i know the opposite is possible using using BMethod in the A declaration.
cheers
If you want to selectively hide functions from B it does not make much sense to use public inheritance in the first place.
Use private inheritance & selectively bring methods from B into the scope of A:
struct B{
void method1(){};
void method2(){};
};
struct A : private B{
using B::method1;
};
A a;
a.method1();
a.method2(); //error method2 is not accesible
There is an issue here: this would be a direct violation of the Liskov Substitution Principle, namely A would not act as a B any longer.
If you wish to reuse B implementation, the solution is simply to do so:
class A
{
public:
void foo() { return b.foo(); }
void bar() { return b.bar(); }
// ...
private:
B b;
};
Don't abuse inheritance, use composition instead
The using keyword can be used to change visibility
struct A
{
void method1();
};
struct B: public A
{
void method2();
private:
using A::method1;
};
Aside from the ways described in the previous answers—composition, private inheritance, and non-private inheritance but with the inherited method declared private—another way is to explicitly delete the inherited method:
#include <iostream>
struct A {
void foo() { std::cout << "foo\n"; }
};
struct B : A {
void foo() = delete;
};
int main() {
B b;
b.foo(); // COMPILER ERROR
}
Although the b.foo() call produces a compiler error, client code can still call the base class’s version by qualifying with the base class identifier A:
b.A::foo(); // compiles, outputs 'foo' to console
This explicit deletion way works when foo is not a virtual non-deleted method in A. By C++11 Standard §10.3/16, this explicit deletion is ill-formed when the deleted method in the derived class overrides a virtual non-deleted method of the base class. For more info on this restriction, see the answers to the SO question C++11 Delete Overriden Method.
You can't "hide it" per se, but you can make it a compile time error to call it. Example:
struct A
{
void AMethod() {}
};
class B : public A
{
void AMethod() {} //Hides A::AMethod
};
int main()
{
B myB;
myB.AMethod(); //Error: AMethod is private
static_cast<A*>(&myB)->AMethod(); //Ok
return 0;
}
Examples on codepad with the error, and without.
That all said, despite this being possible, you really shouldn't do it. You'll confuse the hell out of clients.
EDIT: Note that you can also do this with virtual functions (And with the error).
To those that are suggesting composition... this might not be the best possible way of going about things. My understanding is that the Liskov Substitution Principle only states that there's the possibility of the functions from the base class being used on the child, not that they necessarily should be. For example, for a particular base class you may have multiple functions that essentially perform the same operation, but for different specific cases. In the derived class you may want to abstract these public functions away in favor of simplifying the user's interface. This is where private inheritance can be used. Private inheritance might also be a necessity, if we have protected functions in the base class that we don't want the user of the base class to call, yet would be invaluable to the derived class.
In short, if you HAVE to, use private inheritance, but composition is preferred in most cases.
There is yet another approach.
class A{
void f1();
void f2();
void f3();
}
class BInterface{
void f2();
void f3();
}
class B : public A, BInterface
{
}
BInterface b = new B();
b->f1(); //doesn't work since f1 is not declared in BInterface
b->f2(); //should work
b->f3(); //should work
delete(b);
Use BInterface as a filter for inherited classes to exclude undesirable methods. Liskov Substitution principle isn't violated in this case since an object of BInterface class is not an object of A class even though that an object of B class is an object of BInterface class.
If the methods are private in B, then they will remain hidden to a even if you use public inheritance.
Can't alter the visibility of the original method.
You could create a method in struct A with the same name and have that method be private, but that doesn't prevent the method from being called when an instance of struct A is being referenced by a variable of type B.
Why don't you make it Virtual in the base class and override it in its Children? (more help)
Just a small annoyance really as I can work around the problem by wrapping the derived function instead of using the 'using' keyword but why doesn't the following work (the compiler tells me that 'get_elem' is still pure virtual in 'Bar' class).
class Elem {};
class DerivedElem : public Elem {};
class Foo {
public:
virtual Elem& get_elem() = 0;
};
class Goo {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Foo, public Goo {
public:
using Goo::get_elem;
};
int main(void) {
Bar bar;
}
Cheers,
Tom
If Goo is a "mixin" designed to implement the interface Foo in a particular way (there could be other mixins with other implementations), then Goo can derive from Foo (instead of Bar doing so).
If Goo isn't designed to implement the interface Foo, then it would be a terrible mistake to treat Bar as though it had implemented that pure virtual function, when it fact it just happens to have a function of the same signature. If you want implicit interfaces and "duck" typing in C++ you can do it, but you have to do it with templates. Rightly or wrongly, pure virtual functions are for explicitly declared interfaces, and Goo's get_elem function is not explicitly declared to implement Foo::get_elem. So it doesn't.
I guess that doesn't explain why in principle the language couldn't define using Goo::get_elem for Foo;, or some such declaration in Bar, to avoid the need for Bar to contain a lot of boilerplate wrapping the call.
You can maybe do something with templates to allow Goo to support this to some extent, without really knowing about Foo:
template <typename T>
class Goo : public T {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Goo<Foo> {};
class Baz : public Goo<Fuu> {};
Where Fuu is some other interface that has a get_elem function. Obviously it's then the responsibility of the author of Bar to ensure that Goo really does implement the contract of Foo, and the same for Baz checking the contract of Fuu.
By the way, this form of covariance is a bit dodgy. Looking at Foo, someone might expect the expression bar.get_elem() = Elem() to be valid, and it isn't, so LSP is violated. References are funny like that. ((Foo &)bar).get_elem() = Elem() is valid but in general doesn't work! It only assigns to the Elem sub-object, and for that matter so does ((Foo &)bar).get_elem() = DerivedElem(). Polymorphic assignment is basically a nuisance.
In your example, the Foo and Goo are separate classes. In Bar, the method get_elem from Goo is not at all the same with the one in Foo, even if their signature match.
By having using Goo::get_elem, you simply tell the compiler to resolve unqualified call to get_elem() to the one in Goo.
You've encountered one of the many odd corners of C++. In this case C++ does not consider two virtual functions inherited from different classes to be the same function even though they have the same name and type signature.
There are some good reasons for C++ to act this way. For example, it's frequently the case that those two functions really aren't the same, despite the fact they have the same name and type signature. The semantic meaning of the two functions are different.
Here is an example:
namespace vendor1 {
class Circle {
public:
virtual ::std::size_t size() const { return sizeof(*this); }
};
} // namespace vendor1
namespace vendor2 {
class Shape {
public:
virtual double size() const = 0;
};
class Circle : public Shape {
public:
virtual double size() const { return radius_ * radius_ * M_PI; }
};
} // namespace vendor2
And then you try this:
namespace my_namespace {
class Circle : public ::vendor1::Circle, public ::vendor2::Circle {
// Oops, there is no good definition for size
};
So you have to resort to this:
namespace my_namespace {
class Vendor1Circle : public ::vendor1::Circle {
public:
virtual ::std::size_t data_structure_size() const { return size(); }
};
class Vendor2Circle : public ::vendor2::Circle {
public:
virtual double area() const { return size(); }
};
class Circle : public Vendor1Circle, public Vendor2Circle {
// Now size is still ambiguous and should stay that way
// And in my opinion the compiler should issue a warning if you try
// to redefine it
};
So, C++ has good reason to treat virtual functions with the same type signature (the return type is not part of the type signature) and name from two different bases as different functions.
As far as using goes... All a using directive says is "Add the names from this other namespace to this namespace as if there were declared here.". This is a null concept as far as virtual functions are concerned. It merely suggests that any ambiguity when using a name should be resolved a different way. It only declares a name, it doesn't define the name. In order for a virtual function to be overridden a new definition is required.
OTOH, if you put in a simple thunk redefinition inline like this:
class Bar : public Foo, public Goo {
public:
virtual DerivedElem& get_elem() { return Goo::get_elem(); }
};
a good compiler should see that and know to not even bother to create the function, and instead just fiddle the virtual table entries to do the right thing. It may need to actually emit code for it and have the symbol available in case its address is taken, but it should still be able to simply fiddle the virtual table into having the function completely disappear when called through a Foo *.
Let's say I have the following class hierarchy:
class Base
{
protected:
virtual void foo() = 0;
friend class Other;
};
class Derived : public Base
{
protected:
void foo() { /* Some implementation */ };
};
class Other
{
public:
void bar()
{
Derived* a = new Derived();
a->foo(); // Compiler error: foo() is protected within this context
};
};
I guess I could change it too a->Base::foo() but since foo() is pure virtual in the Base class, the call will result in calling Derived::foo() anyway.
However, the compiler seems to refuse a->foo(). I guess it is logical, but I can't really understand why. Am I missing something ? Can't (shouldn't) it handle this special case ?
Thank you.
When you qualify a method name with a class name, as in Base::foo() dynamic dispatch (run-time binding) does not apply. It will always call the Base implementation of foo(), no matter if foo() is virtual or not. Since in this case it is pure virtual, there is no implementation and the compiler complains.
Your second problem is that in C++, friendship is not inherited. If you want Other to have special access to Derived, it needs to be a friend of Derived specifically.
This, on the other hand, works:
Base* a = new Derived();
a->foo();
Because here, you are calling foo() on a Base* where foo() is public, and since you are not qualifying foo() with a class name, it uses dynamic dispatch and ends up calling the Derived version of Foo.
I guess You could do this
void bar()
{
Base* a = new Derived();
a->foo();
};
However, the compiler seems to refuse that.
Refuse what? It sounds like you are saying that the compiler is refusing to allow Other to call the foo() function through a Base pointer. That certainly shouldn't be the case.
To answer your basic question, friendship is not inherited....period. Permission scope is checked at the same stage as name resolution and since foo() is protected within the names you are using, you can't call it.
Polymorphism on the other hand is resolved through pointer redirection and has nothing to do with name resolution or access permission.
Try put this "friend class Other;" in the derived class.
Update: Now think of it, I agree with Tyler that you should change a to a Base pointer.
Base* a = new Derived();
It's unfortunate, but friendliness is inherently broken in C++ in my opinion:
Not inherited
Give unrestricted access to all the internals, no possibility to restrict it
I've given up using it "as-is" and I now mostly use the Key pattern (for lack of a better name).
///
/// Key definition
///
class Friend;
class FriendKey: boost::noncopyable { friend class Friend; FriendKey() {} };
///
/// Base/Derived definition
///
class Base
{
public:
void mySpecialMethod(const FriendKey&) { this->mySpecialMethodImpl(); }
private:
virtual void mySpecialMethodImpl() = 0;
}; // class Base
class Derived: public Base
{
public:
private:
virtual void mySpecialMethodImpl() {}
}; // class Derived
///
/// Friend definition
///
class Friend
{
public:
void mySpecialCall()
{
Derived d;
d.mySpecialMethod(FriendKey());
}
}; // class Friend
The concept is simple: each class declares a key (possible even in the forward header), and those that wish to grant special access to them will only make it possible for this key.
It's not perfect, because you can of course abuse it (by transitivity of the key). But then in C++ you can abuse everything, so it's more a problem of protected against Murphy than Machiavelli.