Segmentation fault when using Used-defined conversion operator - c++

I have implemented the following piece of code
#include <iostream>
#include <memory>
class A
{
public:
int a;
virtual ~A()
{
}
};
class B : public A
{
public:
int b;
virtual ~B()
{
}
};
class E : public B
{
public:
~E()
{
}
};
class D
{
public:
operator std::shared_ptr<A>()
{
std::shared_ptr<A> pa = std::make_shared<A>();
pa->a = this->y;
return pa;
}
operator std::shared_ptr<B>()
{
std::shared_ptr<A> pb = std::make_shared<B>();
pb = *this;
(std::static_pointer_cast<B>(pb))->b = this->x;
return std::static_pointer_cast<B>(pb);
}
virtual ~D()
{
}
int x;
int y;
};
int main()
{
D d;
d.x = 6;
d.y = 7;
std::shared_ptr<E> pE = std::make_shared<E>();
std::shared_ptr<A> pa = pE;
std::shared_ptr<B> pB = std::dynamic_pointer_cast<B>(pa);
pB = d;
std::cout << "a " << pB->a << "b " << pB->b << std::endl;
return 0;
}
What I try to do is to convert the instance of class D, d, in a instance of shared pointer B which is derived from class A.
The B inherits the class A, and E inherits the class B.
When the program terminates, the program crashes in the destructor of class A.
I used GDB and see that this is NULL.
Does anyone have an idea why this happens?

Inside of D::operator std::shared_ptr<B>(), the use of std::static_pointer_cast<B>(pb) is undefined behavior, because pb does not point at an instance of B at that point, so it is illegal to cast the A pointer to a B pointer and access B's members. pb is pointing at the instance of A created by std::make_shared<A>() in D::operator std::shared_ptr<A>(). On the statement pb = *this;, you are discarding the B object you created and taking ownership of the A object that *this returns.
Thus, inside of main(), pB ends up pointing at an invalid B object and tries to destruct that object when main() exits, which is why you end up crashing the A destructor.
Had you used dynamic_pointer_cast instead of static_pointer_cast inside of D::operator std::shared_ptr<B>(), you would have ended up with a NULL pointer and likely crashed inside of D::operator std::shared_ptr<B>() when accessing B::b, instead of crashing in main().
You need to fix your operator std::shared_ptr<B>() to operate on a valid instance of B, not on an instance of A. For example:
operator std::shared_ptr<B>()
{
std::shared_ptr<B> pb = std::make_shared<B>();
std::shared_ptr<A> pa = *this;
*static_pointer_cast<A>(pb) = *pa; // <-- copy pa->a to pb->a ...
// or: simply do this instead:
// pb->a = pa->a;
pb->b = this->x;
return pb;
}

Related

About virtual functions

I have the following code snippet:
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
public:
int x;
A(int i = 0): x(i) {}
A minus(){
return 1 - x;
}
virtual void print(){
cout << x << "\n";
cout << "Base print\n";
}
};
class B: public A{
int y;
public:
B(int i = 0) {x = i;}
void print(){
cout << x << "\n";
cout << "Derived print!\n";
}
};
int main(){
A* p1 = new B(18);
*p1 = p1->minus();
p1->print();
return 0;
}
The output is:
-17
Derived print!
I know where -17 comes from. It does upcasting and A* p1 = new B(18) and makes p1 point to a derived object with x value of 18. *p1 = p1->minus make the object that p1 points to be an A(-17) /// cause 1 -18 = -17. My question is, where does the second line come from ? If p1 points to an A object after the *p1 = p1->minus(), why does p1->print() not print "Base print" ?
You created an object of the type class B
A* p1 = new B(18);
So the pointer p1 will point to this object until it (the pointer) will be reassigned.
In this statement
*p1 = p1->minus();
the dynamically created object of the type class B was not deleted. Only its sub-object of the type class A was changed using the implicitly defined by the compiler copy assignment operator of the class A and the pointer p1 still points to the same object of the type class B.
Thus in this statement
p1->print();
there is called the virtual function of the object of the type class B that by the way should be declared in the class B at least like
void print() override
{
//..
}
Pay attention to that you should declare a virtual destructor in the class A. For example
virtual ~A() = default;
And before exiting main you should delete the dynamically allocated object.
delete p1;

When I get a case of `slicing`?

Let's look the next code (for example):
class A {
int n;
public:
int f() const { return n; }
void set(int i) { n = i; }
};
class B : public A {
public:
int g() const { return f()+1; }
};
void h(const A& a) {
a.f();
}
int main() {
B b;
A& a = b;
A* ptrA = new B;
h(b);
delete ptrA;
return 0;
}
Now, Let's look about these lines code:
A& a = b; // Is there "slicing"? (why?)
A* ptrA = new B; // Is there "slicing"? (why?)
A a = b; // Is there "slicing"? (why?)
I do not really understand when I want to use any of them, and when, alternatively, you will not be allowed to use one of them. What is really the difference between these lines..
Slicing is when you assign a derived object to a base instance. For example:
B b;
A a = b;
The issue here is that the copy constructor for A that is being called only sees the A part of B, and so will only copy that. This is an issue if your derived class has added additional data or overridden the behaviour of A.
When you assign an object to a reference or a pointer there is no slicing. So
A &a = b;
Is fine, as is:
A *a = &b;

Can a pointer to subclass be assigned to varibale with type of superclass?

Suppose there is a class A which has two subclasses, Aa and Ab. I want to make an array that can store pointers to objects of class Aa and Ab. If an array is declared with the type of class A, is this valid? If not, how can I accomplish this? For example:
A *arr;
//space allocated
Ab *obj1;
arr[x] = obj1;
On a related note, I want to write a function that when given a location, will return the object stored at that location in the array. If the above works and I have an array of objects of either Aa or Ab, the function could return an object of either type Aa or Ab. If the return type of the function is specified as A, the superclass, is this valid? If not, I have looked at template functions but cannot find a straight answer about just having the return type be variable, not the parameters. For this example, the function's parameter is always going to be int, but it could return an Aa or an Ab, depending on what is at that location in the array.
Yes that is the way polymorohism is achieved (using pointer to base class) and virtual methods.
Here is an example:
#include <iostream>
using namespace std;
#include <vector>
class A{
public:
virtual void foo()const{
std::cout << "A::foo()" << std::endl;
}
};
class Aa : public A {
public:
virtual void foo()const{
std::cout << "Aa::foo()" << std::endl;
}
};
class Ab : public A {
public:
virtual void foo()const{
std::cout << "Ab::foo()" << std::endl;
}
};
int main(){
A* ptrA[3];
A* a = new A;
Aa* aa = new Aa;
Ab* ab = new Ab;
ptrA[0] = aa;
ptrA[1] = ab;
ptrA[2] = a;
for(int i(0); i != 3; ++i)
ptrA[i]->foo();
delete a;
delete aa;
delete ab;
return 0;
}
Remember that C++ is Invariant not Contravariant which means you cannot assign a derived object a base object:
A* a = new A;
Ab* ab = a; // error
Is valid to have an array of base pointers, also you can use dynamic_cast to know in run time the return type of your array and use the API from the derived class. See and example below.
struct Base { virtual void do_something() {} };
struct Derived1 : Base
{
void first() const { std::cout << "first" << std::endl; }
void do_something() override {}
};
struct Derived2 : Base
{
void second() const { std::cout << "second" << std::endl; }
void do_something() override {}
};
Base& get(int option)
{
static std::vector<Base*> b {new Derived1{}, new Derived2{}};
return !option ? *b[0] : *b[1];
}
int main()
{
const int option {0};
// const int option {1};
if (Derived1* derived {dynamic_cast<Derived1*>(&get(option))})
{
derived->first();
}
else if (Derived2* derived {dynamic_cast<Derived2*>(&get(option))})
{
derived->second();
}
}

concept of virtual functions in c++

I am trying to understand the concept of virtual function in C++ and I read it online but I am not able to understand why the below program output is 2 instead of 1? Can anyone explain?
Class A
{
int a;
public:
A()
{
a = 1;
}
virtual void show()
{
cout <<a;
}
};
Class B: public A
{
int b;
public:
B()
{
b = 2;
}
virtual void show()
{
cout <<b;
}
};
int main()
{
A *pA;
B oB;
pA = &oB;
pA->show();
return 0;
}
you achieve polymorphism with overriding virtual functions and pointers:
in your example you used pA polymorphically so it is a pointer to a base class (A) but you but you assign to it a class B's object which is child of A.
and you you declared Show() as virtual.
this is the main goal of polymorphis; which means we don't know the type of object the base pointer points to until runtime eg in main:
int main()
{
int choice;
cout << "1: A object 2: B object:\n\n";
cin >> choice;
if(1 == choice)
pA = new A; // result will be 1
else
if(2 == choice)
pA = new B; // result will be 2
if(pA)
pA->show();
delete pA;
pA = NULL;
// B* pB = new A; // error: cannot convert from class A* to class B* because C++ is not contravariant
B* pB = new B;
pB->show(); // result: 2
delete pB;
pB = NULL;
return 0;
}
From cppreference
Virtual functions are member functions whose behavior can be overridden in derived classes. As opposed to non-virtual functions, the overridden behavior is preserved even if there is no compile-time information about the actual type of the class. If a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class. This behavior is suppressed if the function is selected using qualified name lookup (that is, if the function's name appears to the right of the scope resolution operator ::)
Since, you are overriding show() in class B, pA->show() will call show() in class B.Hope this helps

Polymorphism with references does not behave as expected

As I understand it, polymorphism with references should work exactly as it does with pointers.
However, consider the following example: the calls to doer() are correctly dispatched when using pointers, but the "B version" seems to be called in both case when using a reference.
I cannot figure out the reason why the following example is behaving in the way it does. Why is the "B version" called in both cases when using a reference?
#include <iostream>
class B;
class C;
void doer(B *x) {
std::cout << "B version" << std::endl;
}
void doer(C *x) {
std::cout << "C version" << std::endl;
}
class A {
public:
virtual ~A() {}
virtual void doit() = 0;
};
class B: public A {
public:
virtual void doit() override {
doer(this);
}
};
class C: public A {
public:
virtual void doit() override {
doer(this);
}
};
int main() {
B b;
C c;
A *a = &b;
a->doit(); // B version gets called, OK
a = &c;
a->doit(); // C version is called, OK
A &d = b;
d.doit(); // B version is called, OK
d = c;
d.doit(); // B version is called again??
}
Here you assign a reference:
A &d = b;
d.doit(); // B version is called, OK
Here you overwrite the object reffered to by d with c (it's no longer the definition of a reference):
d = c;
d.doit(); // B version is called again??
That's the main difference between references and pointers. A reference is like a constant pointer that you can only assign at definition. Afterwards, whenever you use the reference, it means the object you've referred to.
In fact when you do d = c; some slicing occurs. The object d is in fact a B, but the operator= from A is called, copying only member data of A.
Here how to demonstrate this statement:
class A {
public:
...
A& operator= (A a) {
cout << "A::operator=" << endl; // just to show what happens when d=c is called
return *this;
}
};
class B : public A {
public:
int x; // add some variables for B
virtual void doit() override {
cout << "B::doit() " << x << endl;
doer(this);
}
};
class C : public A {
public:
int a,b; // add aditional variables for C
virtual void doit() override {
cout << "C::doit() " << a << ","<<b << endl;
doer(this);
}
};
...
b.x = 123; // put some class specific variables in C
c.a = 222; c.b = 333; // put some class specific variables in C
A &d = b; // assignement of the reference. d reffers to a b object
d.doit(); // B version is called, OK
d = c; // but an A object is copied (so only A subobject of c is taken
// to overwrite A subobject of d)
d.doit(); // B version is called becaus again?? => yes !! because it's still a B
// And you see that the B part of the object is left intact by A::operator=
cout << typeid(d).name() << endl;
// remember at this point that d still refers to b !
References are bound by their referent for their entire lifetime, and, unlike pointers, require initialization. Using the assignment operator calls the assignment operator of the referent, and does not reassign the reference:
A &d = b;
d = c;
Here d = c calls the assignment operator from the base class A subobject contained in d, and copies the A subobject data contained in c.