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*
}
Related
I have an interface in C++ that looks something like this:
// A.h
#pragma once
class A
{
public:
//Some declarations.
private:
//Some declarations.
protected:
//Some declarations.
};
The specific form is not important. Since this is an interface, there will be a class B that inherits from A. In the header file for class B I have:
// B.h
#pragma once
class B : A
{
public:
//Some declarations.
private:
//Some declarations.
protected:
//Some declarations.
};
My concern is that I tend to use class B : A instead of class B : public A, just my bad memory.
So far I have had no issues with this, since it's a small enough project. But will forgetting the public keyword affect my project in any sense?
Or more succinctly, I know how access modifiers work but, what does class B : A default to?
The ONLY difference between struct and class is that in a struct, everything is public until declared otherwise, and in a class, everything is private until declared otherwise. That includes inheritance. So class B : A will default to private inheritance, and struct B : A will default to public inheritance.
What does class B : A default to?
class B : private A { /*...*/ }
But will forgetting the public keyword affect my project in any sense?
Yes. Don't forget it.
Consider the following:
// A.h
class A {
public:
void f(){}
};
// B.h
class B : A {};
int main() {
B b;
b.f(); // f is inaccessible because of private inheritance
}
I've 2 classes (voluntary as simple as possible) and I'm working with Qt on Mac OS X:
//Class A
class A
{
protected:
int getX(){return _x;};
private:
int _x;
};
//Class B
class B : A
{
void method(){qDebug() << this->getX();}
};
And the compiler throws:
error: 'getX' is a private member of 'A'
Am I missing something?
I've tried with:
qDebug() << this->A::getX();
Which doesn't work either!
When you don't specify the type of inheritance the default is taken as private.
In private inheritance,
Base Class' public members are private.
From standard docs, 11.2.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.
there are three types of inheritance:
public
protected
private
the dafult mode for class is private, and for struct it is public:
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.
[From C++ standard, 11.2.2]
So, when you say:
class B: A
this is private inheritance and thus all public and protected members of a base class will be inherited as private. What you need is
class B: public A
or
class B: protected A
Private and protected inheritance is used more often where defining implementation details. Private bases are most useful when defining a class by restricting the interface to a base so that stronger guarantees can be provided. For example, Vec adds
range checking to its private base vector (§3.7.1) and the list of pointers template adds type checking to its list<void*> base -> see Stroustrup ("C++..." §13.5).
Example:
//Class A
class A
{
public:
int getX(){return _x;};
protected:
int getX2(){return _x;}
private:
int _x;
};
//Class B
class B : protected A //A::getX and A::getX2 are not visible in B interface,
^^^^^^^^^ // but still we can use it inside B class: inherited
// members are always there, the inheritance mode
// affects only how they are accessible outside the class
// in particular for a children
{
public:
int method(){ return this->getX();}
int method2(){ return this->getX2();}
};
int main(int argc, char** argv) {
B b=B();
printf("b.getX(): %d",b.method()); // OK
printf("b.getX(): %d",b.method2()); // OK
return 0;
}
Further effects to inheritance
Additionally, when you declare class as
class B: A
being the same as class B: private A further inheritance becomes unavailable: only class that derives from A and its friends can use A public and protected members. Only friends and members of B can convert B* to A*.
If A is a protected base then its public and protected members can be used by class B and its friends and by classes derived from B and their friends. Only friends and members of B and friends and members of class derived from B can convert B* to A*.
If A is a public base finally, then its public members can be used by any class and its protected members can be used by derived classes and their friends and by classes derived from B and their friends. Any function can convert B* to A*.
Note also that you cannot cast constness with dynamic_cast or static_cast, it is said that they both respect constness. They both respect access controls also (it is not possible to cast to a private base [because only derived class methods might do Derived* -> Base* and methods of classes being friends to this {friend declaration is in Base}])
more in Stroustrup ("C++", 15.3.2)
When you inherit a class from another, the mode of inheritance should be mentioned. So, you have to declare as
class B: public A
Then you won't have the error
Try this:
//Class A
class A
{
protected:
int getX(){return _x};
private:
int _x;
};
//Class B
class B : public A
{
void method(){qDebug() << this->getX();}
};
You forgot the keyword public, you don't use this as a pointer and you forgot the ; at the end of the classes.
Your code should be as follows:
class A {
protected:
int getX() { return _x; }
private:
int _x;
};
//Class B
class B : public A {
void method() { this->getX(); }
};
They were many errors:
class B: public A;
this->getX();
commas after class declarations
You forgot ; in your getter return
int getX() { return _x; };
To begin with, I know about C++ Standard (ISO/IEC 14882:2003): Section 11.5, Paragraph 1, and this is not that case (but compliler apparently does not think so).
I try to call protected base class method in derived class method through this pointer, static-casted to base class pointer and have in MSVC2008 error C2248: 'A::f' : cannot access protected member declared in class 'A'.
I have to do this in context of 'curiously recurring template pattern', but I can reproduce this error in simplier code, as follows:
class B
{
protected:
void f(){}
};
class D : public B
{
public:
void g()
{
f(); // ok
this->f(); // ok
static_cast<B*>(this)->f(); // C2248 in MSVC2008
dynamic_cast<B*>(this)->f(); // C2248
((B*)this)->f(); // C2248
}
};
D d; d.g();
It seems that compiler think of casted this pointer as a pointer to other instance, yeah?
The compiler is wrong in this case, what do you think?
Ok, my real code is more like that:
template<class T>
class B
{
public:
void g()
{
f(); // error C3861: 'f': identifier not found
this->f(); // error C3861: 'f': identifier not found
// static_cast to derived class
static_cast<T*>(this)->f(); // C2248 in MSVC2008
}
};
class D : public B<D>
{
protected:
void f(){}
};
I cast this to derived class, and I can't use this->f();
By the way, I see that this code is unsafe for usage like class E : public B<D> {...};: compilable, but static_cast makes wrong cast.
The compiler is correct. To explicitly access the B::f member function, you can write:
this->B::f();
The relevant language is:
c++11
11.4 Protected member access [class.protected]
[...] Access to a protected member is granted because the reference occurs in a friend or member of some
class C. [...] Access to a protected member [...] involve[s] a (possibly implicit) object expression (5.2.5). In this case,
the class of the object expression shall be C or a class derived from C.
Thus protected member access via a cast to the base class B violates this grant, and is disallowed. It is also unnecessary for the reason that you can use this->B::f() as above.
In the case with your actual CRTP motivation, you are correct that you cannot call f() without a static_cast, since D is not a base class of B<D> (the inheritance relationship is in the other direction). Since D is not a base class of B<D>, you cannot call its protected methods from B<D> anyway. One simple workaround is to friend B<D> to D and use the static_cast on the this pointer:
template<typename T>
class B {
public:
void g() {
static_cast<T *>(this)->f();
}
};
class D : public B<D>
{
friend class B<D>;
...
If giving B access to the private parts of D worries you, you can move the private parts to another base class and isolate the CRTP mechanism in D:
template<class T> class B {
public:
void g() {
static_cast<T*>(this)->f();
}
};
class C {
private:
void h();
protected:
void f(){ std::cout << "D::f\n"; }
};
class D: protected C, public B<D>
{
friend class B<D>;
};
Here B<D> is prevented from calling C::h as friendship is neither inherited nor transitive.
I think the compiler is right.
Suppose the following:
void g()
{
B *b1 = this;
B *b2 = GetUnrelatedB();
b1->f(); //Error?
b2->f(); //Error!
}
The b1 case is equivalent to your static_cast but it would be very strange that b1 will be allowed and b2 will not.
Citing your paragraph 11.5:
[...] the access must be through a pointer to, reference to, or object of the derived class itself.
But static_cast<B*>(this) is of type B*, not D*, no matter that the object itself is the same. Actually, the value of the pointer is irrelevant to this issue, only the type of the expression:
void g()
{
B *b2 = GetUnrelatedB();
static_cast<D*>(b2)->f(); //ok!
}
But, how would the compiler know that you are inside a class derived from B once you apply static_cast on this? In my (humble) opinion, if I create a B object, I expect not to be allowed to call private or protected B methods on the B object, since we don't want to violate encapsulation. It would not matter where the B object is created, as long as it's outside of the B class methods.
By 'promote' I mean make access more restrictive and by 'demote' I mean make less restrictive.
For example, when class B is derived from class A using : protected or : private then the public members of A get promoted, to protected and private, respectively.
Could some class C ever come in and derive itself from class B, while at the same time demoting the inherited members of class A back to their original access specifications?
If you're using protected derivation, then class C could indeed give access to the protected members, by creating an appropriate wrapper:
class A {
public:
void F();
};
class B : protected A { };
class C : public B {
public:
using B::F;
};
This also can be made to work with data members:
class A {
public:
int n;
};
class B : protected A { };
class C : public B {
public:
using B::n;
C() : n(this->B::n) { }
};
With private inheritance this is not directly possible, because C cannot itself access members in A.. However, if B is derived from A using private virtual inheritance, it becomes possible again:
class A {
public:
void F();
};
class B : private virtual A { };
class C : public B, public virtual A { };
int main() {
C x;
x.F();
return 0;
}
This works because with virtual inheritance, C can derive directly from the same instance of A as B, but with a different access specifier.
A using declaration can give access to public or protected members of protected base classes:
struct A {int x;};
struct B : protected A {};
struct C : B
{
using A::x; // publicly accessible
}
Obviously, private members and base classes aren't available to C, so you can't reduce the restrictions on them.
Of course not, what would be the point of having private or protected inheritance if I can just create another derived that class that blows away the intermediate class' access restrictions and makes everything public?
No.
Because, when class C derives class B; it doesn't know about the original access specifiers of class A. It just respects the access specifiers in class B.
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.