I made following 3 classes:
struct Parent1
{
virtual void f()
{
cout << "\nParent1::f";
}
};
struct Parent2
{
virtual void g()
{
cout << "\nParent2::g";
}
virtual void z()
{
cout << "\nParent2::z";
}
};
struct Child : public Parent1, public Parent2
{
virtual void h()
{
cout << "\nChild::h";
}
};
In main, when I call function z of Parent2, it instead calls function h of the child class. Why is it happening so?
Following is the main function:
int main()
{
Child obj;
Parent2 * p2 = (Parent2*)(Parent1*)&obj;
p2->z();
return 0;
}
The first explicit conversion from &obj i.e. Child* to Parent1* is an upcast. The result will point to the base class sub-object. The next explicit conversion is from Parent1* to Parent2*. Since these classes are not directly related, this is a reinterpretation cast. But the types are not pointer-interconvertible, so when you call the function through the reinterpreted pointer, the behaviour of the program is undefined.
You should avoid using C-style casts to prevent mistakes like this. In this case, no explicit cast is needed at all. This works correctly:
Parent2 * p2 = &obj;
And never reinterpret pointers unless you know what it means and that it is OK to do so.
Related
I have the following code:
struct A
{
virtual void foo() {std::cout << "A\n";}
};
struct B : public A
{
virtual void foo() {std::cout << "B\n";}
};
void bar(A * a)
{
a->foo();
}
Without changing this code, is it possible to cast bp pointer to B, so calling bar would print "A"?
int main()
{
B * bp = new B();
bar(/* do somethig*/ bp);
return 0;
}
Tried every cast I remebered:
int main()
{
B * bp = new B();
bar((A*)bp);
bar(static_cast<A*>(bp));
bar(reinterpret_cast<A*>(bp));
bar(dynamic_cast<A*>(bp));
return 0;
}
You could make a shim wrapper around B, and have the shim's virtual function dispatched to BWrap::foo() call directly to A::foo();.
There's not really any point in the example to carrying along the B& member variable reference, but for more interesting examples there may be a use case.
struct BWrap : public A
{
B& b;
BWrap(B& bb) : b{bb} {}
virtual void foo() { b.A::foo(); }
};
int main()
{
B* bp = new B();
BWrap bw{*bp};
bar(&bw);
}
If you insist on the A object being a base class subobject of a B object and on not modifying the first code snippet at all, then the only solution is to add an even more derived class that can override the virtual call as explained in the answer by #Eljay (which I completely forgot to think about when first writing this answer).
Other options are to create a complete A object, not a B object, or to modify bar to do a call without virtual dispatch by using a qualified name:
a->A::foo();
All of the casts you are showing have the same effect as the implicit conversion, except for reinterpret_cast which will cause undefined behavior when used this way.
I define 2 classes
class BaseA {
public:
virtual void methodA() = 0;
};
class BaseB {
public:
virtual void methodB(int val) = 0;
};
Child inherits 2 Base Class
class Child : public BaseA, public BaseB {
public:
void methodA() override {
printf("Child A\n");
}
void methodB(int val) override {
printf("Child B %d\n", val);
}
};
Then I write following code.
void callBaseB(void *p) {
BaseB *b = (BaseB *) p;
b->methodB(0);
}
int main() {
auto child = new Child;
callBaseB(child);
return 0;
}
console print
Child A
Why this happened? Why not call method B?
(This is what happend when a Java engineer try to write C++ code)
You should just do this: void callBaseB(BaseB *p) {p->methodB(0);}.
If you want to keep void *p as a parameter, you need to cast it to exactly Child * first. Either:
BaseB *b = (Child *)p;
b->methodB(0);
Or:
Child *b = (Child *)p;
b->methodB(0);
Alternatively, cast to BaseB * before converting to void *. Then casting from void * back to Base * will work.
What happens here is that the BaseB subobject is at non-zero offset inside of Child.
When you convert Child * to BaseB * (either explicitly with a cast, or implicitly, either by assigning pointers or by calling a method of BaseB on the pointer), the compiler automatically offsets the pointer by the required amount, to point to the BaseB subobject.
The offset is determined entirely at compile-time (unless virtual inheritance is involved), based on the two types.
When you obscure the source type using void *, the compiler has no way to determine the correct offset, and doesn't even try to apply any offset, so you get weird behavior, because the resulting BaseB * doesn't point to a BaseB instance, but rather to some junk inside of Child.
Even with virtual inheritance, despite the offset being determined at runtime, the calculation depends on the source pointer type being known.
Casting a void* to a BaseB* cannot be done (as #PaulSanders said), but you can definitely cast a Child* to a BaseB* as follows:
void callBaseB(Child* p)
{
BaseB* b = p;
b->methodB(0);
}
The above code should successfully call methodB().
But if you really need to use void*, you can so something like this:
void callBaseB(void* p)
{
Child* b = (Child*)p;
b->methodB(0);
}
This question already has answers here:
accessing a protected member of a base class in another subclass
(8 answers)
Closed 7 years ago.
I always thought that I understood inheritance, but obviously I don't. I would like to call a protected member function of another instance of the same parent class from a child class like in the following example code:
#include <iostream>
class Parent {
protected:
void doStuff(){
std::cout << 5 << std::endl;
}
};
class Child : public Parent {
public:
void pubfunc(Parent* p){
p->doStuff();
}
};
int main(){
Child* c = new Child();
Parent* p = new Parent();
c->pubfunc(p);
return 0;
}
However, compilation of this code fails with:
In member function ‘void Child::pubfunc(Parent*)’:
error: ‘void Parent::doStuff()’ is protected
error: within this context
I wouldn't want to make the Child class a friend of the Parent class to avoid forward declarations and forward includes of child classes as much as possible. Also, I don't want to make doStuff public, because it can really mess up the internal structure of Parent when used in the wrong circumstances.
Why does this error happen, and what is the most elegant way to solve it?
Mostly the problem is that if C++ allowed you to access the non-public members of the referent of a base class pointer directly, then you could gain easy access to the data of an object simply by deriving from a common base.
Still this is a known loophole in the C++ type system, as shown below, where you can gain that access without modifying the base class, and without using casts or anything like that.
On the third and gripping hand, what you should do is to support the intended usage directly in the base class, by adding a static member function there, as follows:
#include <iostream>
using namespace std;
class Base
{
protected:
void doStuff()
{
cout << 5 << endl;
}
static void doStuff( Base* p ) { p->doStuff(); }
};
class Derived : public Base
{
public:
void pubfunc( Base* p )
{
doStuff( p );
}
};
auto main() -> int
{
Derived d;
Base b;
d.pubfunc( &b );
}
In my humble opinion this is most clear and elegant.
But for completeness, the type system loophole:
#include <iostream>
using namespace std;
class Base
{
protected:
void doStuff()
{
cout << 5 << endl;
}
};
class Derived : public Base
{
public:
void pubfunc( Base* p )
{
(p->*&Derived::doStuff)();
}
};
auto main() -> int
{
Derived d;
Base b;
d.pubfunc( &b );
}
I recommend the static member function, though.
Protected members are accessible in the class that defines them and in classes that inherit from that class. Sometimes it causes people to be confused when they see this kind of errors. But in fact you call doStuff function for Parent object, it doesn't meter if function call done inside inherited class. The result will be the same if you call doStuff function from main().
class Parent
{
protected:
virtual void doStuff()
{
std::cout << 5 << std::endl;
}
};
class Child : public Parent
{
protected:
void doStuff() override
{
std::cout << 8 << std::endl;
}
public:
void pubfunc(Parent* p)
{
((Child*)p)->doStuff();
}
};
int main()
{
Child* c = new Child();
Parent* p = new Parent();
c->pubfunc(p); // will print 5
c->pubfunc(c); // will print 8
return 0;
}
class Base1
{
public:
virtual ~Base1(){}
virtual void whatever()
{
cout << "whatever" << endl;
}
};
class Base2
{
public:
virtual ~Base2(){}
virtual void aFunc(int i) = 0;
};
class A : public Base1, public Base2
{
public:
A()
{}
~A()
{}
virtual void aFunc(int i) final
{
cout << "func" << endl;
}
};
int main()
{
void* a;
a = new A();
(static_cast<Base2*>(a))->aFunc(0);
Base2* ptr = static_cast<Base2*>(a);
ptr->aFunc(0);
return 0;
}
This example prints out "whatever" instead of "func", if I change the line with void* to A* than it prints out "func". Is this a known behavior? I would expect that's the case just don't know why.
Is this a known behavior?
Yes. Behaviour is well-defined if you convert to void* and then back to the same type. It's undefined if you convert back to a different type.
I would expect that's the case just don't know why.
There's no guarantee that a base sub-object has the same address as the complete object; in fact, if there's more than one non-empty base class, then at least one sub-object will have to be at a different address. So a valid conversion from A* to Base2* probably needs to adjust the value of the pointer, not just reinterpret it as a different type. Conversion to void* and back can't make that adjustment.
I have a function that looks like:
// this function might modify base_ptr
void SomeFunction(shared_ptr<Base> &base_ptr)
{ if(some_condition) { base_ptr = some_other_ptr; } }
I'd like to call the function with a shared_ptr:
shared_ptr<Derived> d = ...;
SomeFunction(d);
This doesn't work though. It doesn't work if I'm using normal pointers either (ie. implicit casting to Base* & from Derived*. One workaround is to create a Base pointer from the Derived one, and then pass that to the function.
shared_ptr<Base> base = d;
SomeFunction(b);
But this isn't very pretty from a coding standpoint. It also adds confusion and the potential for a subtle bug:
shared_ptr<Derived> d = derived;
shared_ptr<Base> b = derived;
SomeFunction(b);
// b and d might now be pointing to different things -- not good!
Is there better way to do this?
What you are trying to do is inherently dangerous, and C++ is making it hard on purpose. Consider if C++ allowed you to call SomeFunction the way you wanted. Then you could do this:
struct Base {
};
struct Derived1 : Base {
void f1();
};
struct Derived2 : Base {
void f2();
};
void SomeFunction(shared_ptr<Base> &p)
{
p = make_shared<Derived2>(); // nothing wrong with converting
// a Derived2 pointer to a Base pointer.
}
int main()
{
shared_ptr<Derived1> d = make_shared<Derived1>();
SomeFunction(d); // An error, but what if it wasn't?
d->f1(); // Trying to call method f1 of a Derived2!
}
The compiler would not be able to know that d changed from a Derived1 pointer to a Derived2 pointer, so it wouldn't be able to give you a compile error when you tried to call method f1 of a Derived2.
You could template the function for the smart pointer's type
#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;
class Base {
public:
virtual void hello() {
cout << "hello base" << endl;
}
};
class Derived : public Base {
public:
void hello() {
cout << "hello derived" << endl;
}
};
class otherClass {
public:
};
template<typename T>
void SomeFunction(shared_ptr<T> &base_ptr)
{
static_assert(is_base_of<Base, T>::value == true, "Wrong non-derived type");
base_ptr->hello();
// Rebase it
base_ptr.reset(new Derived);
base_ptr->hello();
}
int main() {
shared_ptr<Base> obj(new Base());
SomeFunction(obj);
// hello base
// hello derived
shared_ptr<Derived> obj2(new Derived());
// hello derived
// hello derived
SomeFunction(obj2);
shared_ptr<otherClass> obj3(new otherClass());
SomeFunction(obj3); // ASSERT
return 0;
}
http://ideone.com/ATqhEZ
If you intend to update all the smart pointers when you reset one, you'll have to do some book-keeping by yourself since they're not designed to have a "signal-like" mechanism to notify other smart pointers pointing to the same object.
Edited my answer to provide compile-time safety if you intend to use it with Base and relative subclasses.
Warning: the above solution uses C++11, the same could be accomplished in a similar way in pre-C++11 code