When compiling the following example in msvc, I get
'Interface' not accessible because 'Base' uses 'private' to
inherit from 'Interface'
in the line marked with Error. When the call to foo is qualified with a type alias of the same type, it works. I tested with msvc and ideone.
Why are the two calls not equal?
struct Interface {};
template<class T>
struct Base : private T
{
void foo() {}
};
using BaseX = Base<Interface>;
class Derived : Base<Interface>
{
Derived() {
Base<Interface>::foo(); // Error
BaseX::foo(); // Works
}
};
Ideone
Injected-class-names.
The name Interface is injected into the scope of the class Interface as if it's a public member, and in turn inherited by Base<Interface> (as a private member, since you are using private inheritance).
When you write Base<Interface>::foo() in Derived, unqualified name lookup for Interface looks first at Derived and its base class, finds Interface in the base class, and then access control kicks in because that name is private.
The simplest fix is to just write Base::foo(), or even just foo() if it isn't virtual and you aren't planning to write a foo() in Derived.
If you have to include the template argument for some reason, then write Base<::Interface>.
Related
Due to the layout of a third-party library, I have something like the following code:
struct Base
{
static void SomeStaticMethod(){}
};
struct Derived1: private Base {};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Base::SomeStaticMethod();
}
};
int main() {
Derived2 d2;
d2.SomeInstanceMethod();
return 0;
}
I'm getting compiler error C2247 with MSVC:
Base::SomeStaticMethod not accessible because Derived1 uses private to inherit from Base.
I know I can't access Base members from Derived2 via inheritance because of the private specifier, but I should still be able to call a static method of Base - regardless of any inheritance relationship between Base and Derived2.
How do I resolve the ambiguity and tell the compiler I'm just making a call to a static method?
Do this:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
I think michalsrb's answer is better, but for completeness:
namespace
{
void SomeStaticMethodProxy()
{
return Base::SomeStaticMethod();
}
}
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
SomeStaticMethodProxy();
}
};
will also work.
Other answers provide way to solve the problem, I'll try to explain what's happening. It's because of injected-class-name.
9.2 (N4594)
[...]The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name.[...]
Note that even if you type Base::SomeStaticMethod(), obviously SomeStaticMethod is looked up in Base scope (It's qualified name), but name Base itself also has to be looked up somehow, (In this example as an unqualified name (because it does not appear after scope resolution operator))
What happens is that when you search for (unqalified) name Base in Derived2, first Derived2 scope is searched, then Derived1 scope is searched and then Base scope is searched and finally injected-class-name is found. Then access control takes place (because access control takes place after name lookup) and it'll find that name you looked up is Base's member which isn't accessible from Derived2.
You can do this if you want to call it through the hierarchy:
struct Derived1: private Base {
protected:
using Base::SomeStaticMethod;
};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Derived1::SomeStaticMethod();
}
};
Otherwise, do as #michalsrb mentioned if you want to call it directly on Base.
A couple of possibilities:
Don't use the inheritance structure to call the method. Use ::Base::SomeStaticMethod() to call it. Base is accessible in the global namespace.
Bring the private function into the namespace of Derived1 by writing using Base::SomeStaticMethod;
I'm trying to publicly derive a class from a template that will make it inherit from a base class and get access on protected members. But before the template is expanded it doesn't have those rights, so it can't use a Base member as a template parameter:
using Fun = void (*)();
class Base {
protected:
// friend class Derived; // ...need this to eliminate complaint
static void something();
};
template<Fun F>
class Variant : public Base {};
class Derived : public Variant<&Base::something> { // `something()` is protected
public:
void somethingElse() {
something(); // doesn't complain about this `something()`
}
};
int main() {}
The weird bit about this to me was that friending it worked at all. I wondered if I might "sneak Derived in the door" by putting a public virtual inheritance from Base before the Variant:
class Derived : public virtual Base, public Variant<&Base::something>
That didn't help.
Question: is there some other trick for avoiding explicit mention of all derived classes in Base, yet still have access to pick protected members out of it for template parameters?
(Note: Trying this on an older gcc, 4.6.3, looks like even the friending doesn't help in that case. So it seems support for that is somewhat new.)
Stick the offending access into a metafunction. Derive the metafunction class from the base.
template<typename B>
struct something_variant : public B {
typedef Variant< & B::something > type;
};
class Derived : public something_variant<Base>::type {
…
http://coliru.stacked-crooked.com/a/6bca00455bd3daca
Regarding CWG 372, the critical text in the resolution is this:
[A]ccess checking of base-specifiers must be deferred until the entire base-specifier-list has been seen.
This was already accepted in C++11, so it's interesting that your example is rejected. And, plugging the relevant example code from the C++11 standard into recent Clang and GCC demonstrates that they simply did not implement the deferral. It's at least a little unsurprising, since implementation requires some data structure to represent a set of deferred access checks… fairly high effort for a corner case.
I would like to know if there's a way to make a method from a derived class a friend of its base class. Something like:
class Derived;
class Base
{
int i, j;
friend void Derived::f();
protected:
Base();
};
class Derived : public Base
{
public:
void f();
};
The errors I got were:
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
error: C2248: 'Base::i' : cannot access private member declared in class 'Base'
see declaration of 'Base::i'
see declaration of 'Base'
error: C2248: 'Base::j' : cannot access private member declared in class 'Base'
see declaration of 'Base::j'
see declaration of 'Base'
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
I struggled with it during all the day. Everything I found about friendship use only separated classes, not inheritance.
No there is no direct way : Base needs the definition of Derived::f while Derived also needs the definition of it's Base class.
But it does not matter, you should not do that, you can, in order of preference :
Provide protected accessors in the Base class
Make the entire Derived class a friend (not necessary in general)
You can use an intermediate helper class which only forward the call of this specific method, and give it friendship :
Example here:
class Base;
class Derived;
class Helper final
{
friend class Derived;
public:
void f(Base* base);
private:
Helper() {}
};
class Base
{
int i, j;
friend class Helper;
protected:
Base() {}
};
class Derived : public Base
{
public:
void f();
private:
Helper helper;
};
void Helper::f(Base* base)
{
base->i = 10; base->j = 5;
std::cout << "Help !" ;
}
void Derived::f()
{
helper.f(this);
}
One approach for this kind of problem is to apply the rule "if it's a thing, then it's a class."
#quantdev solution is on those lines.
Based on the comment:
assuming that I have two classes both derived from base class and
having an identical private member. Why not saving some codes by
putting that member in the base class and providing a friend access to
both derived classes that need the member. Assuming that other derived
classes won't be able to access that member at all. That's what I'm
trying to achieve
[I know that this does not answer the specified question, but may be what you need.]
I'd solve that by factoring the common element into an intermediate class:
class Base
{
public:
Base();
virtual ~Base() = 0;
};
class Derived : public Base
{
public:
void f()
{
i = 1;
}
private:
int i, j;
};
class Foo : public Derived
{};
class Bar : public Derived
{};
class Fred : public Base
{};
I don't know if it is possible to do exactly what you want (although it seems to me like it should be) -- and I'd be interested to see other answers that show how if it is -- but there are a few other ways to achieve what you want. I assume you are asking about this situation in general -- that is, you are also interested in the case where there can be many different derived classes, not all of which need, no should have access to the private fields of Base (otherwise you should make these fields protected of course).
First, the easiest thing to do would be to make Derived a friend class to Base, although this feels like a hack (in part because it doesn't allow for any encapsulation of Base with respect to Derived) and is definitely sub-optimal here.
In my opinion, a somewhat better approach in terms of encapsulation would be to make an external "free" (non-member) function that is a friend to Base (and potentially Derived if you need that too). This gets around the circular compiler error, but unfortunately still loses the conceptual semantics of being an "operation on Derived".
Can you inherit the same class twice? E.g. :
class Base {
};
class Foo : public Base {
};
class Bar : public Base {
};
class Baz : public Foo, public Bar {
//is this legal?
// are there restrictions on Base
// (e.g. only virtual methods or a virtual base)?
};
Yes it is legal, and no there are no restrictions on Base.
You should however be aware that this causes two different objects of type Base to exist within Baz, which will require you to use qualified names to tell C++ which version of Base you mean, when you try to access its members.
C++ provides a mechanism called virtual inheritance to solve this problem (if it is a problem for you):
class Base { };
class Foo : public virtual Base { };
class Bar : public virtual Base { };
class Baz : public Foo, public Bar { };
This will share the Base object between the Foo and Bar objects within Baz
C++ does support multiple inheritance.
The syntax for class Baz is correct.
See this tutorial for some caveats and more information: http://www.cprogramming.com/tutorial/multiple_inheritance.html
Yes, it's legal to inherit the same class twice.
If the inheritance is non-virtual, as in your example (I just fixed the syntax and formatting),
class Base {};
class Foo : public Base {};
class Bar : public Base {};
class Baz : public Foo, public Bar {};
then it's generally necessary to qualify any use of something from such duplicate base.
If however each direct inheritance of the common base is virtual (using the keyword virtual), then there is only one common sub-object of the common base. This is the so called diamond pattern of inheritance in C++. It's a bit tricky, e.g. in that it yields at least one sub-object spread over a non-contiguous region of memory, and in that it's the most derived class that is responsible for initializing the common virtual base. Also it introduces some inefficiency and is associated with some compiler bugs. So it's seldom used, but sometimes it's necessary – e.g., it can emulate Java interface inheritance, and it can be used to emulate Java final (not necessary in C++11).
Yes, it is legal, but having two subobjects of the same Base class causes many difficulties, because you always must explicitly say which one you want, using the scope operator ::.
Baz x;
Base& y = x; // Illegal because ambiguous.
Base& y = (Bar&)x; // Now unambiguous.
Part of that trouble can be solved by inheriting Base using virtual inheritance, which makes sure only exactly one Base.subobject exists.
In that case, the virtual base is always initialised by the most derived constructor, before all non-virtual bases.
class Base {}
class Foo : public virtual Base {}
class Bar : public virtual Base {}
class Baz : public Foo, public Bar {}
Baz x;
Base& y = x; // Legal, because even though both direct bases inherit from `Base`,
// they do so virtually, thus there is only one Base subobject
Base& y = (Bar&)x; // Still unambiguous.
Now, if Foo used protected or private inheritance, you could not cast down to Foo::Derived in Baz or completely outside in the first (non-virtual) example.
In the virtual example, you could, because that sub-object is also reachable using Bar, and the most accessible path determines the access rights.
This is legal.
But restrictions arise when classes are labeled protected and private classes before it. For this, its respective functions and attributes are protected and private.
My friend has shown me the follow code
struct A {
virtual void f() = 0;
virtual void g() = 0;
};
struct AInternal : A {
virtual void f() { /* ... */ }
virtual void g() { /* ... */ }
};
He is using AInternal as an internal class that implements most (if not all of A). He then inherited from AInternal, but as he wanted that AInternal stays inaccessible (since it is an implementation detail), he inherits protected (implemented in terms of). What he also did was usinging the base class name to make A accessible (it was protected by default, since AInternal was inherited protected too)
struct C : protected AInternal {
using AInternal::A;
};
Actually, this worked fine (but as we later found, it still kept the member functions private - just the base class was made public), but it only worked on GCC. It fails to make base A accessible. Any idea? We could even make it to break code that works on Clang
struct C : public AInternal {
protected:
using AInternal::A;
};
C *c = 0;
A *a = c; // error on GCC!
Can someone help out please?
You are only affecting the visibility of the injected-class-name. The access protection of the base subobject or its members should not be affected. If Clang or GCC allows it to affect a cast validity or access within the base, that's their bug.
[class.member.lookup] 10.2/3 says
In the declaration set, using-declarations are replaced by the members they designate, and type declarations (including injected-class-names) are replaced by the types they designate.
The base class subobject does not have a name in member lookup; the injected-class-name does.