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
};
Related
I have base class called Base and a derived class of Base called Derived,
A Base Class pointer can point to a derived class object and can also access its resource but I am getting an error doing the same.
class Base
{
public:
int a;
};
class Derived : public Base
{
public:
float b;
void DoSomething()
{
cout<<"Derived";
}
};
int main()
{
Base * pBase = new Derived();
pBase->DoSomething();
pBase->a = 5;
pBase->b = 0.2f;
return 0;
}
This gives me an error
main.cpp: In function ‘int main()’:
main.cpp:34:25: error: ‘class Base’ has no member named ‘DoSomething’
pBase->DoSomething();
^
main.cpp:36:12: error: ‘class Base’ has no member named ‘b’
pBase->b = 0.2f;
^
Pardon me if its too basics, I am a beginner in c++
Yes you can use a Base pointer to a Derived class, nonetheless, the Base pointer must know the methods in order to choose what's the most suited for the call, if the Base pointer has no knowledge of the existence of these variables and functions it cannot call them.
Corrected code:
class Base
{
public:
int a;
float b;
virtual ~Base(){} //virtual destructor required
virtual void DoSomething() //implementing DoSomething in base class
{
std::cout << "Base";
}
};
class Derived : public Base
{
public:
void DoSomething() override //override DoSomething() in base class
{
std::cout<<"Derived";
}
};
Base * pBase = new Derived();
//Base will choose the most suited DoSomething(), depending where it's pointing to
pBase->DoSomething();
pBase->a = 5;
pBase->b = 0.2f;
Output:
Derived
Edit:
As you suggested in the comment section, casting the derived class will work in this specific case, but it usually reveals poorly designed code, as pointed out by #user4581301's comment, also note the link provided that has some of the reasons why this is not the best idea.
As I said, if you must do it, use dynamic_cast<>() instead.
Note that, in any case, you still need the virtual destructor for a correct implementaion of polymorphism.
Virtual destructors
Deleting an object through pointer to base invokes undefined behavior unless the destructor in the base class is virtual.
and that's not all, check this link.
I am trying to send a derived pointer to a base class's function through another one of the Base class's functions, but for some reason, it complains:
error: invalid use of incomplete type 'struct Derived' on line 8.
#include <iostream>
using namespace std;
class Derived;
class Base
{
public:
void getsomething(Derived *derived){derived->saysomething();} //This is line 8
void recieveit(Derived *derived){getsomething(&*derived);}
};
class Derived : public Base
{
public:
void giveself(){recieveit(this);};
void saysomething(){cout << "something" << endl;}
};
int main()
{
Base *b = new Base;
Derived *d = new Derived;
d->giveself();
return 0;
}
do you know how I could fix this?
You can't use forward declaration, when the compiler needs information about the class's members.
A forward declaration is only useful for telling the compiler that a class with that name does exist and will be declared and defined later.
So do like following :
class Derived ;
class Base
{
public:
void getsomething(Derived *derived);
void recieveit(Derived *derived);
};
class Derived : public Base
{
public:
void giveself(){recieveit(this);};
void saysomething(){cout << "something" << endl;}
};
void Base::getsomething(Derived *derived){derived->saysomething();}
void Base::recieveit(Derived *derived){getsomething(&*derived);}
The only way is to take the function definitions out of the class declaration and put them after the declaration of Derived. At the point you're trying to use them, the poor compiler doesn't even know what methods exist on Derived yet.
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.
struct B {};
struct D : private B {
B* fun () { return new D; } // ok
}
struct DD : public D {
B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
};
This error seems unreasonable to me. If we can use simple B* in global scope then why not in its privately derived classes? g++ demo.
We are Not trying to convert DD* to B*, which is forbidden by the language rules (this, this, this are related questions).
Note that, if I change B* foo() to int foo(), things go fine.
So apparently the compiler thinks B is referring to the private constructor of B rather than the type.
Qualifying B apparently fixes that error:
class B* foo () { return 0; }
or this:
::B* foo () { return 0; }
I don't know why that's happening, but maybe this will help.
Update: maybe it's related to 11.2.4 of standard? The only problem is that my standardese isn't good enough to fully understand it.
(sorry for the image, copy/pasting isn't working for me)
A quick look-up for injected-class-name in the Standard yields:
§11.1 [class.access.spec]
5/ [ 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
};
—end example ]
I believe this is eerily close to your example ;)
Note clang 3.0's stack, which is slightly more explicit:
$ clang++ -fsyntax-only test.cpp
test.cpp:6:5: error: 'B' is a private member of 'B'
B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
^
test.cpp:2:12: note: constrained by private inheritance here
struct D : private B {
^~~~~~~~~
test.cpp:1:8: note: member is declared here
struct B {};
^
1 error generated.
Here we see that B is accessed through D, instead of directly picked up in the global namespace.
My best guess is that it's not forbidden, C++ simply doesn't see the B type inside that statement or in better terms the label B means nothing.
Some good read about
http://eli.thegreenplace.net/2012/02/06/dependent-name-lookup-for-c-templates/
https://stackoverflow.com/a/7376212/1797612
List of C++ name resolution (and overloading) rules
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.