I recently had to do something like this:
class A { };
class B : private A { };
class C : public B {
public:
A *myA;
};
int main() {
return 0;
}
And I get an error in the three compilers I tried. When I changed the declaration of myA to ::A *myA everything works ok. I poked around in the C++ standard and found Section 11.2, paragraph 3 where it says:
Note: A member of a private base class might be inaccessible as an inherited member name, but accessible directly.
Which is relevant, but unclear. Why is the name A inaccessible? What problems would occur if A was not hidden?
Thanks,
-Ben
Where it could "go wrong":
namespace nmsp
{
class A {};
}
class A {};
class B : private nmsp::A
{
// well-formed:
A* d; // refers to the injected-class-name nmsp::A!!
};
class C : public B
{
// ill-formed
A* p; // refers to the injected-class-name nmsp::A!!
};
It should not depend on the access-specifier in the base-clause whether ::A or nmsp::A is used, otherwise it'd be error-prone IMO.
Related
Why does class D compile, but class C does not?
class A
{
public:
A(int) {}
};
template <class T>
class B : private T // Note: private base class
{
public:
using T::T;
};
class C : public B<A>
{
public:
C() : B<A>(123) {} // Error: 'class A A::A' is inaccessible
}; // within this context
using BA = B<A>;
class D : public BA
{
public:
D() : BA(123) {} // OK
};
I tested with GCC, Clang and Visual C++, and they are all the same.
Changing class B : private T to public T solves the problem. But why? (Note that the using T::T is public.)
Class A contains the injected-class-name A within its scope (that is, A::A refers to class A unless it happens to refer to the constructor).
Class B inherits this, so the name A within the scope of B refers to the injected-class-name A in scope of A. However, since A is a private base class of B, all names in scope of A are private within B.
Class C again inherits this, but it cannot access this A, since it is private within B. Hence the error. Note that the error is actually with using the name A in the construct B<A>.
Class BA doesn't have this problem, since the definition B<A> is not in the scope of any class, so the name A refers to the global name A and not to any injected-class-name. And of course, the name BA is public.
You can easily solve this by qualifying the name A in C:
class C : public B<A>
{
public:
C() : B<::A>( 123 ) {}
};
Note that constructor inheritance has no effect there. The problem is with access to the class name A (injected in A and inherited in B and C), not with access to the constructor.
In the grammar of C++ Specification, the members of a class is defined as this:
member-declaration:
decl-specifier-seq(optional) member-declarator-list(optional);
function-definition ;(optional)
::(optional) nested-name-specifier template(optional) unqualified-id ;//what is this?
using-declaration
template-declaration
...
I understand 4 of them. But the 3rd one defines a mandatory nested name specifier followed by an id. e.g
class {
X::Y::z;
}
I don't aware of any C++ syntax that matches this definition. Did I miss something?
The answer is to be found in the [class.access.dcl] section. To put shortly, such a declaration is called 'access declaration' and its purpose is to change access level for an inherited member.
For example:
class A
{
protected:
int a;
int a1;
};
class B
{
public:
int b;
int b1;
};
class C : public A, private B
{
public:
A::a;
B::b;
}
int f()
{
C c;
c.a1; // access error: A::a1 is protected
c.b1; // access error: B is private base of A
c.a; // accessible because A::a is 'published' by C
c.b; // accessible because B::b is 'published' by C
}
This sort of declaration was superseded by using, but kept for compatibility purposes.
class A {
public:
void fa() {
}
};
class B : public A{
public:
void fb() {
}
};
class C : public A, public B {
public:
void fc() {
//call A::fa(), not B::A::fa();
}
};
How to call A::fa() from C::fc() function.
GCC warns withdirect base A inaccessible in C due to ambiguity, does this mean there is no direct way to refer base class members?
One option would be to create a stub class that you can use for casting to the right base class subobject:
struct A {
void fa() { }
};
struct B : A {
void fb() { }
};
// Use a stub class that we can cast through:
struct A_ : A { };
struct C : A_, B {
void fc() {
implicit_cast<A_&>(*this).fa();
}
};
Where implicit_cast is defined as:
template <typename T> struct identity { typedef T type; }
template <typename T>
T implicit_cast(typename identity<T>::type& x) { return x; }
I just found the following info from ISO C++ 2003 standard (10.1.3)
A class shall not be specified as a direct base class of a derived class more than once. [Note: a class can be
an indirect base class more than once and can be a direct and an indirect base class. There are limited
things that can be done with such a class. The non-static data members and member functions of the direct
base class cannot be referred to in the scope of the derived class. However, the static members, enumerations
and types can be unambiguously referred to.
It means there is no direct way :(
I just compiled you code on codepad.org , putting A::fa() is enough to call fa() from your C::fc() function.
void fc() {
A::fa();
}
The below is the link to codepad with your code.
http://codepad.org/NMFTFRnt
I don't think you can do what you want. There is an ambiguity here: when you say A::fa(), it still doesn't tell the compiler which A object to use. There isn't any way to access class A. That's what the warning is telling you.
This seems like an awfully strange construct, though. Public inheritance should be used for is-a relationships. You are saying that C is-a A twice over? It doesn't make sense. And that suggests that this is either an artificial example that would never come up in practice, or you should reconsider this design.
You can use virtual inheritance to overcome such problem:
class B : virtual public A {
Now, you can use A::fa() simply in the child class C.
void fc()
{
fa();
}
However, I generally don't see any practical need to inherit class A again into class C, when B is already publically inheriting A. So, In your case, you can make it simple:
class C : public B {
Edit:
If you want 2 instances for A. then the direct instance which you are intending can be made as an object of C:
class C : public B {
A obj;
Because, having a directly inherited A will not be usable in anyway. You cannot declare any pointer or reference to it inside the scope of C.
I have the following code example that doesn't compile:
#include <stdio.h>
namespace my
{
class base1
{ // line 6
};
class base2: private base1
{
};
class derived: private base2
{
public:
// The following function just wants to print a pointer, nothing else!
void print(base1* pointer) {printf("%p\n", pointer);}
};
}
The error that gcc prints is:
test.cpp:6: error: `class my::base1'
is inaccessible
test.cpp:17: error: within this
context
Now, i can guess what the problem is: when looking at the declaration of print, the compiler sees base1 and thinks: base1 is the base-class subobject of derived* this, but you don't have access to it! While i intend that base1 should be just a type name.
How can i see in the C++ Standard that this is a correct behavior, and not a bug in the compiler (i am sure it's not a bug; all compilers i checked behaved so)?
How should i fix this error? All the following fixes work, but which one should i choose?
void print(class base1* pointer) {}
void print(::my:: base1* pointer) {}
class base1;
void print(base1* pointer) {}
Edit:
int main()
{
my::base1 object1;
my::derived object3;
object3.print(&object1);
}
The section you're looking for is 11.1. It suggests using ::my::base1* to work around this:
[ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. — end note ]
[ Example:
class A { };
class B : private A { };
class C : public B {
A *p;
// error: injected-class-name A is inaccessible
:: A * q ;
// OK
};
If I have for example two classes A and B, such that class B inherits A as follows:
class B: public A
In this case, I'm doing public inheritance.
If I write the previous code as follows:
class B: A
What type of inheritance will I be doing here (i.e; public)? In other words, what is the default access specifier?
Just a side question here. Do I call the previous line of codes statements? Especially that I remember I read in the C++ Without Fear: A Beginner's Guide That Makes You Feel Smart book that statements are that that end with ;. What do you think about that?
Thanks.
Just a small addition to all the existing answers: the default type of the inheritance depends on the inheriting (derived) type (B in the example), not on the one that is being inherited (base) (A in the example).
For example:
class A {};
struct B: /* public */ A {};
struct A {};
class B: /* private */ A {};
It's private for class and public for struct.
Side answer: No, these are definitions of the class according to the standard. Class definition end with a semicolon. On the other hand not all statements end with a semicolon (e.g. an if statement does not).
When you inherit a class from another class (inherit class Base from class Derived in this case), then the default access specifier is private.
#include <stdio.h>
class Base {
public:
int x;
};
class Derived : Base { }; // is equilalent to class Derived : private Base {}
int main()
{
Derived d;
d.x = 20; // compiler error becuase inheritance is private
getchar();
return 0;
}
When you inherit a class from a structure (inherit class Base from struct Derived in this case), then the default access specifier is public.
#include < stdio.h >
class Base {
public:
int x;
};
struct Derived: Base {}; // is equilalent to struct Derived : public Base {}
int main() {
Derived d;
d.x = 20; // works fine becuase inheritance is public
getchar();
return 0;
}
If you use class to define your class, the default access specifier will be private. (I think it's wrong, too.) If you use struct, however, it will be public.
And class definitions are declarations, I think. A statement is what translates into actual code (unless optimized away, anyway).
However, a mildly exotic feature of C and C++ is that expressions are statements. That's why 3+4; is a syntactically legal statement in C++ (although many compilers will warn about it having no effect). While it is obviously nonsense in this case, in general expressions are evaluated for their side effects. (An obvious example is discarding a function's return value. You call the function not to obtain a result, but for its side effects.)
The "type" of inheritance depends on how the class is defined. There are default access specifiers applied to inheritance. From the C++ standard:
[class.access.base]/2
In the absence of an access-specifier for a base class, public is
assumed when the derived class is defined with the class-key struct
and private is assumed when the class is defined with the class-key
class. [ Example:
class B { /* ... */ };
class D1 : private B { /* ... */ };
class D2 : public B { /* ... */ };
class D3 : B { /* ... */ }; // B private by default
struct D4 : public B { /* ... */ };
struct D5 : private B { /* ... */ };
struct D6 : B { /* ... */ }; // B public by default
class D7 : protected B { /* ... */ };
struct D8 : protected B { /* ... */ };
Here B is a public base of D2, D4, and D6, a private base of D1, D3,
and D5, and a protected base of D7 and D8. — end example ]
If you do not choose an inheritance, C++ defaults to private inheritance in the same way class members default to private access for classes.
The default type of the inheritance is private in C++.
class B:A
{};
is equivalent to
class B: private A
{};
the default access specifier is an important differentiator between classes and structs. It is public by default for structs and private by default for classes.
AS other casting problem you have
class A { virtual void test() = 0; };
class B : virtual public A { virtual void testb() {} };
class C : virtual public A { virtual void testc() {} };
class D : public B, public C {
virtual void test() override {}
}
void main() {
D d;
void* v = &d;
A* a = &d;
((D*)A)->test(); //OK
((D*)v)->test(); //undefined behavior (that call testb() in vtable logic at 1st inheritance position)
dynamic_cast<D*>(v)->test(); //compile error cast from void* not permitted
//resolution
void* x = a;
((D*)x)->test(); //OK but as you can see, you must to store a* in x*
}