Can someone explain why this code doesn't work.
class A
{
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
};
class B : public A
{
public:
B(void){parent = new B;}
~B(void){delete parent;}
protected:
int a;
};
class C : public B
{
public:
C(void){}
virtual ~C(void){}
void f(void){ ((B*)parent)->a; }
};
How is it possible that C isn't able to access members of B?
If I convert parent to a C* in stead of a B* it works fine. But I don't want users to take any unnecessary risks. Is there a cleaner way access a?
Thanks.
From an object of the C class, you can access protected members of B, but only if they're part of some object of class C (maybe yours, maybe not). In other words, to access a from C, you need a pointer (or a reference) to C. This is what the protected modifier means.
The reason for this is the following. The ((B*)parent) pointer may point to some other subclass of B, completely different from C, and that subclass may have the a member inaccessible.
Related
The situation is (hopefully) clear with the code. We have two (in this example pure abstract, but that isn't necessary) classes. Is this possible to define the class C? What happens to the pointer c_ptr? Do I need to delete it in the class B destructor?
class C : public B {
private:
public:
C();
~C();
int do();
};
class B : public A {
private:
C *c_ptr;
public:
B(){
c_ptr = new C();
}
~B() {
delete c_ptr;
}
virtual int do() = 0;
};
class A {
private:
public:
A();
~A();
virtual int do() = 0;
};
In short, no, this is not possible.
In your example we have the following constraints:
B is child of A
C is child of B is child of A
For every super class, there must be an object created as well. So for the instantiation of a B, there will be created an A first.
The same way for a C there will be constructed a B which will create an A first.
As C++ is a procedural language, datatypes and functions must be known BEFORE using them. However, it is not possible for the compiler to know how to build a C before knowing how to build a B and vice versa. Therefore it is not possible to do so.
However, this polymorphism structure may be accomplished by using something called Forward Declaration. Basically you tell the compiler that there is some class C which will be specified later on. Example in CompilerExplorer
This question already has answers here:
Access to method pointer to protected method?
(7 answers)
Closed 8 years ago.
class A {
public:
A() {auto tmp = &A::foo;}
protected:
void foo() {}
};
class B : public A {
public:
B() {auto tmp = &A::foo;}
};
Class A compiles no problem. Class B yields a compilation error:
'A::foo' : cannot access protected member declared in class 'A'
Why is that, what's the rationale? Is there a way to circumvent this (if I need that pointer for a callback, std::function etc.)?
Why is that, what's the rationale?
In general, a derived class can only access protected members of the same derived class, not of the base class itself or arbitrary classes with the same base class. So B can access protected members of A via B, but not directly via A.
Is there a way to circumvent this?
The inherited member is also a member of B, and can be accessed as such:
auto tmp = &B::foo;
If you were able to take a pointer to A::foo, you could use it to invoke foo on an object of type A or of type C derived from A:
class B : public A {
public:
void xx(A a) { auto tmp = &A::foo; a.*tmp(); } // illegal
}
Instead, take a pointer to B::foo; this is fine because you can only use it on objects of type B, your own class.
Presumably for safety. If you could get a pointer to that member and give it to absolutely anyone without having some kind of alarm bell going off, that would be risky.
Here's a workaround (others may know better):
class A {
public:
A() {auto tmp = &A::foo;}
protected:
void foo() {}
};
class B : public A {
public:
B() {auto tmp = &B::foo;}
};
EDIT - thought you might need a using A::foo but you don't even need that. Works without. See:
Access to method pointer to protected method?
You can access it through B, that is :
class B : public A {
public:
B() {auto tmp = &B::foo;}
};
You cannot access &A::Foo from outside B, since it is protected, but you can through inheritance (since Foo becomes a member of B through inheritance), that is, by calling &B::Foo
I know that this code won't work and I also know why, but is there an alternative?
class A
{
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ ((B*)parent)->a; }
};
It is not possible to cast parent to a B*, since A is a virtual base class. Not casting parent also gives an error. I hope I don't have to make all members public. Does someone have an idea how to access A::a?
Edit
Using friends doesn't work, since classes derived from B don't have access to A::a.
Some options:
Make a public
Create a public setter/getter method for a -
make B a friend of class A (or just the function f())
The 3rd option his works better than the other 2 if you want to allow only A (or a specific function) to have access to members of A. On the other hand with the other 2 options you can make only that member public (but it will be public to everyone)
Making an answer from my comment above because I tested it and it compiles fine.
Without the cast, it probably fails because you are trying to access a protected field of A in B. You can just add a public getter and remove the cast to B*
class A
{
public:
A(void){}
virtual ~A(void){}
int getA() { return a; }
protected:
A* parent;
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ (parent)->getA(); }
};
This works:
class A {
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
int a;
int parent_a(){ return parent->a;}
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ A::parent_a(); }
};
Note that:
a doesn't get exposed to the outside world,
the retrieved a is necessary the correct one, since B inherit virtually from A, so a successful dynamic cast of parent to B before getting its a field should return the same one as the solution offered above.
Now, why does this work?
Because a class is implicitely friend of itself.
That's what dynamic_cast is for. If you don't want to redesign your code, just replace the C-style cast with a dynamic_cast:
void f() { dynamic_cast<B*>(parent)->a; }
For this to work correctly, A must have at least one virtual function (as this one does). In addition, the cast will produce a null pointer if parent does not, in fact, point to an object of type B.
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
protected:
void f(){ this->a; }
};
you're allowed to access protected member from parent class (A mother class of B).
I think the problem here is not so much how to access the element a, but why you need a tree of diamond hierarchies in your design. You should at first step back and evaluate if you really need a tree of diamonds.
If you do, then instead of your current approach, provide A with a nice appropriate (public) abstract interface that can be called from B. When you start accessing parent protected attributes directly you tightly couple components, making it easy to break your code and making it very hard to change your design later in the application's lifespan.
Thanks everyone, some usable possibilities were mentioned, like using friends and creating additional functions for each variable. This could work in some scenarios, but not in my case. Adding each derived class as a friend has the problem that it makes the library less user friendly when they want to add a class. Adding functions per variable would add over hundred extra functions for some classes.
What I did as my final solution was creating a copy instead of a cast. Though it will run a little bit slower, the code will remain clean. To counter the speed problem. Accessing local variables is a lot faster than accessing global variables.
This is how it looks now:
class A
{
public:
A* parent;
virtual ~A(void){}
virtual A & operator = (const A & x)
{
a = x.a;
parent = x.parent;
return *this;
}
protected:
int a;
};
class B : public virtual A
{
public:
B(void){}
virtual ~B(void){}
using A::operator =;
virtual B & operator = (const B & x)
{
A::operator = (x);
return *this;
}
void f(void)
{
B p;
p = *parent;
int x = p.a;//Allowed.
}
};
If you have a better solution, please feel free post it.
Can someone explain why this code doesn't work.
class A
{
public:
A(void){}
virtual ~A(void){}
protected:
A* parent;
};
class B : public A
{
public:
B(void){parent = new B;}
~B(void){delete parent;}
protected:
int a;
};
class C : public B
{
public:
C(void){}
virtual ~C(void){}
void f(void){ ((B*)parent)->a; }
};
How is it possible that C isn't able to access members of B?
If I convert parent to a C* in stead of a B* it works fine. But I don't want users to take any unnecessary risks. Is there a cleaner way access a?
Thanks.
From an object of the C class, you can access protected members of B, but only if they're part of some object of class C (maybe yours, maybe not). In other words, to access a from C, you need a pointer (or a reference) to C. This is what the protected modifier means.
The reason for this is the following. The ((B*)parent) pointer may point to some other subclass of B, completely different from C, and that subclass may have the a member inaccessible.
C++ : I have a basic object (object A) that contains a member object (object B). The member object interface (object B) needs to be fully exposed through the pointer to object A. What's the best way to do this? I could place the object as a public member but this feels like a hack. I could write wrappers for all B's interface in A but this feels ugly. I could merge the objects but I am doing class serialization to XML so having distinct classes is cleaner. I thought about friend classing but I don't think that applies to this situation.
What is the standard way to resolve this type of issue?
Let B implement an interface IB. A manages an instance of B internally and has a getter getB that returns the IB interface of the private B instance. If you want to protect the B instance, you can make the IB methods const and also hide the destructor (by making it private in IB).
class IB {
private:
~IB();
public:
virtual void method1() = 0;
virtual void method2() = 0;
};
class B : public IB {
public:
virtual void method1() {};
virtual void method2() {};
void destruct() { delete this; }
};
class A {
private:
B myB;
public:
IB *getB() { return &myB; }
};
(This is just to give an idea. It's been 3+ years since I last touched C++. I could have made some blatant errors.)
I reject the notion that doing this at all is a good idea, but I would make it a public member. If you don't like that you can have a getB() method. If possible, I would make it return a const reference instead of a normal reference.
Overload the -> operator in A and in the implementation return the pointer variable of type B.
But as you know you will not be able to access A's members through A's pointer and ->. Also it has the risk of causing confusion who ever read the code.
I meant something like this.
struct A
{
B *p;
B * operator -> ()
{
return p;
}
};