I stumbled upon casting sideways from derived to derived class and discovered a gap in my knowledge. I had been living in a world where this is possible - until now. Instead, std::bad_cast is thrown. What's going on here?
#include <iostream>
class Base
{
protected:
int x_;
public:
Base(int x) : x_(x) {}
virtual ~Base() = default;
int x() const { return x_; }
virtual void setX(int x) = 0;
};
class Editable : public Base // class implements setters
{
public:
Editable(int x) : Base(x) {}
void setX(int x) { x_ = x; }
};
class ReadOnly : public Base // class implements empty setters
{
public:
ReadOnly(int x) : Base(x) {}
void setX(int x) {}
};
int main()
{
Editable editable(4);
ReadOnly &readOnly = dynamic_cast<ReadOnly&>(editable); // std::bad_cast
}
This is what is meant when people say that dynamic_cast can cast sideways:
struct A { virtual ~A() = default; };
struct B { virtual ~B() = default; };
struct D : A, B {};
B* pb = new D();
A* pa = dynamic_cast<A*>(pb); // OK
i.e., it allows you to cast a B* to a A* if the pointer is pointing to something that's derived from both A and B. For the cast to succeed, there still must be an A subobject for the pointer to point to (or the reference to bind to, if you are casting to a reference type).
In your case, e is an Editable. There's no ReadOnly subobject anywhere in there. So the cast fails.
You're not casting sideways.
You're casting from one derived of a base to another.
Let's hypothetically say your cast succeeded, and there's a public int member called readOnlyInt in ReadOnly class.
How can the compiler perform readonly.readOnlyInt?
There's no readOnlyInt in the casted ReadOnly & cause it is in fact an Editable.
Casting sideways involves multiple inheritance structures & looks something like this:
class A {
virtual ~A() {}
};
class B {
virtual ~B() {}
};
class C : public A, public B {
};
int main() {
B *b = new C();
A *a = dymanic_cast<A *>(b);
return 0;
}
Related
How to convert two parent pointers in c++?
This is the code.
// base class
class B {
public:
virtual ~B() {};
// other code
};
class A {
public:
virtual ~A() {};
// other code
};
// child class
class C1 : public A, B {
public:
virtual ~C1() {};
// other code
};
class C2 : public A, B {
public:
virtual ~C2() {};
// other code
};
// ...other C class
There is a std::vector<std::shared_ptr<A>> which items point to instance C1 or C2 ...Cn.
Does anyone know how to convert the vector to a std::vector<std::shared_ptr<B>>?
Your code has typos. Missing public in inheritance of B when defining C<x> breaks stuff.
After this is fixed sidecast does the job as it should:
dynamic_cast conversion - cppreference.com
b) Otherwise, if expression points/refers to a public base of the most derived object, and, simultaneously, the most derived object has an unambiguous public base class of type Derived, the result of the cast points/refers to that Derived (This is known as a "sidecast".)
// base class
class B {
public:
virtual ~B() { }
};
class A {
public:
virtual ~A() { }
};
class C1 : public A, public B {
public:
virtual ~C1() { }
};
class C2 : public A, public B {
public:
virtual ~C2() { }
};
TEST(SideCast, sigleItemCast)
{
C2 x;
A* a = &x;
auto b = dynamic_cast<B*>(a);
ASSERT_THAT(b, testing::NotNull());
}
TEST(SideCast, sideCastOfVectorContent)
{
std::vector<std::shared_ptr<A>> v { std::make_shared<C1>(), std::make_shared<C2>() };
std::vector<std::shared_ptr<B>> x;
std::transform(v.begin(), v.end(), std::back_inserter(x),
[](auto p) { return std::dynamic_pointer_cast<B>(p); });
ASSERT_THAT(x, testing::Each(testing::NotNull()));
}
Live demo
So to summarize I have something equivalent to
class A{
public:
virtual void foo() const = 0;
};
class B : public A{
public:
B(){};
void foo() const override{
//some code
};
};
class C{
public:
C(){};
B someFunction();
private:
A* x;
};
and A* x; points to some B object and I need someFuntion() to return that object that x is pointing to. I've tried just doing return *x but that doesn't work.
You must down-cast the x into B before de-reference.
class C
{
public:
C() {};
B someFunction()
{
return *static_cast<B*>(x); // like this
}
private:
A* x = new B;
};
You need also provide the virtual ~A(), not to have undefined behavior.
When to use virtual destructors?
class A
{
public:
virtual void foo() const = 0;
virtual ~A() = default;
};
If you know that x points to a B object then cast it first.
return *static_cast<B*>(x);
casting shared pointer from B class to A class is not working the console output isn't 12 it's (it outputs A's x but i want B's x)(probably an other memory address). what's wrong with my code
#include <iostream>
#include <memory>
class A
{
public:
int x;
};
class B : public A
{
public:
B(){}
B(const B*){}
int x = 12;
};
std::shared_ptr<A> create()
{
return std::make_shared<B>(new B);
}
int main(){
std::shared_ptr<A> p;
p = create();
std::cout << p->x << std::endl;
std::cin.get();
return 0;
}
A::x and B::x are different objects. Variable access is never polymorphic in C++, so when you access p->x, you're accessing A::x. A::x was never initialized though, so the behavior of your program is undefined.
You need to either have your derived class's constructor initialize the base class's object or delegate that responsibility to the base class's constructor:
class A
{
public:
A(int x) : x{x} {}
int x;
};
class B : public A
{
public:
B() : A{12} {}
};
Live Demo
Alternatively you could wrap x in a virtual accessor method:
class A
{
public:
virtual ~A() = default;
virtual int x() const = 0;
};
class B
{
public:
int x() const override
{
return x_;
}
private:
int x_ = 12;
};
Live Demo
Is there a way to copy a derived class object thru a pointer to base?
Or how to create such a copy constructor?
For example:
class Base {
public: Base( int x ) : x( x ) {}
private: int x;
};
class Derived1 : public Base {
public:
Derived( int z, float f ) : Base( z ), f( f ) {}
private:
float f;
};
class Derived2 : public Base {
public:
Derived( int z, string f ) : Base( z ), f( f ) {}
private:
string f;
};
void main()
{
Base * A = new *Base[2];
Base * B = new *Base[2];
A[0] = new Derived1(5,7);
A[1] = new Derived2(5,"Hello");
B[0] = Base(*A[0]);
B[1] = Base(*A[1]);
}
The question is whether *B[0] would be a Derived1 object and *B[1] a Derived2 object?
If not, how could I copy a derived class thru a pointer to the base class? Is there a specific way of building a copy-constructor thru the base class or the derived one? Is the default copy-constructor good enough for the example?
You may provide virtual method Clone for that:
class Base {
public:
Base(int x) : x(x) {}
virtual ~Base() {}
virtual Base* Clone() const { return new Base(*this); }
private:
int x;
};
class Derived1 : public Base {
public:
Derived1(int z, float f) : Base(z), f(f) {}
virtual Derived1* Clone() const { return new Derived1(*this); }
private:
float f;
};
class Derived2 : public Base {
public:
Derived2(int z, std::string f) : Base(z), f(f) {}
virtual Derived2* Clone() const { return new Derived2(*this); }
private:
std::string f;
};
In the second line of your main (apart from the typo) you construct two instances of the class Base, then you are asking if somehow in the last two lines those objects will metamorphose on the fly and become instances of derived classes. That is of course not possible.
Also, check this answer.
Note: I am just commenting on the code and use case you provided. Using a virtual Clone function is the right design to copy polymorphic objects.
I have the the following classes:
class Base
{
public:
Base() { x = 3; }
int x;
virtual void foo() {};
};
class Med1 : public virtual Base
{
public:
int x;
Med1() { x = 4; }
virtual void foo() {};
};
class Med2 : public virtual Base
{
public:
virtual void goo() {};
virtual void foo() {};
};
class Der : public Med1, public Med2
{
public:
Der() {}
virtual void foo() {};
virtual void goo() {};
};
And the following code:
Base* d = new Der;
d->foo();
cout << d->x;
Output:
3
Why is that? Med1 constructor is called after Base constructor. I'm guessing it's setting Med1::x, and not Base::x, but why is Der::x the same as Base::x and not Med1::x. Why is there no ambiguity?
d is a pointer to Base, so d->x refers unambiguously to Base::x. There would only be an ambiguity if it were a pointer to Der.
Since it is pointer to Base x will be of Base.
And the order of constructor is super class and then derived class. So constructor of Base class is called first and then of Der.
The variable x is not virtual, so the compiler has to scratch its head and say - hang on you Base. Therefore it goes to Base->x