I am learning about polymorphism, and this is something I have stumbled on. I cant find satisfying answer and testing the following code doesnt yield expected result.
#include <stdio.h>
#include <iostream>
class Base {
public:
Base(){
std::cout<<"Constructing Base" << std::endl;
};
virtual int get_a(){
return p_a;
};
virtual int check(){
std::cout<<"check Base" << std::endl; return 2;
};
virtual ~Base(){
std::cout<<"Destroying Base" << std::endl;
};
int p_a = 4;
};
class Derive: public Base {
public:
Derive(){
std::cout<<"Constructing Derive" << std::endl;
};
int get_a(){
return p_a;
};
int check(){
std::cout<<"check Derive" << std::endl;
return 3;
};
~Derive(){ std::cout<<"Destroying Derive" << std::endl; };
int p_a = 2;
};
int main() {
Base *basePtr = new Derive();
delete basePtr;
basePtr->check();
std::cout << "p_a: " << basePtr->get_a() << std::endl;
return 1;
}
Console output :
Constructing Base // line 1
Constructing Derive // line 2
Destroying Derive // line 3
Destroying Base // line 4
check Base // line 5
p_a: 4 // line 6
I see why I get line 1-4, the basePtr is pointer to Derive, which inherits from Base, which implements virtual functions.
My 1. expectation : After calling delete, the pointer basePtr should not be able to deliver the function call ->check(), and also there should be no value p_a.
My 2. expectation : I would expect the value p_a from Derive (p_a = 2), to appear on the output, because basePtr stores the pointer of Derive.
Could someone correct my thinking ?
This is undefined behavior. Whatever results you get, are invalid.
delete basePtr;
This destroys the object.
basePtr->check();
After destroying the object, the shown code attempts to dereference a pointer to the destroyed instance of the class, and invoke a method of the destroyed object. Invoking a method of a destroyed object is undefined behavior.
Related
This question already has answers here:
What is object slicing?
(18 answers)
Closed 3 years ago.
I have two classes, one derived from the other. I want a function that returns an object (not pointer or reference) of the base class that calls the derived virtual function.
#include <iostream>
using namespace std;
class Base
{
public:
virtual void print() { cout << "Base" << endl; }
};
class Derived : public Base
{
public:
void print() { cout << "Derived" << endl; }
};
Base go()
{
Derived *derived = new Derived();
Base *base = derived;
base->print();
// (*base).print(); // prints "Derived" !
// Base base2 = (*base);
// base2.print(); // prints "Base" !
return *base;
}
int main()
{
Base base = go();
base.print();
return 0;
}
This prints out
Derived
Base
So in the go() function I managed to convert to Base and the print works. But when I return the object the print is using the base function!
I know this can work if you return a pointer or a reference but I really need to return an object. Is this possible? Why does my code not work?
As you can see, I've commented out code in go() that de-references the upcast pointer. Strangely, it prints correctly! And if I do a conversion to an object, it doesn't!
Any insight into why this is all happening would be very much appreciated.
When you return an actual object (and not a refernce or a pointer) it calls its copy ctor. In this case you return a Base class, so it calls its copy constructor and creates a new Base class object.
#include <iostream>
using namespace std;
class Base
{
public:
Base() = default;
Base(const Base & base) { std::cout << "COPY BASE" << std::endl; }
virtual void print() { cout << "Base" << endl; }
};
class Derived : public Base
{
public:
Derived() = default;
Derived(const Derived & derived) { std::cout << "COPY DERIVED" << std::endl; }
void print() { cout << "Derived" << endl; }
};
Base go()
{
Derived *derived = new Derived();
Base *base = derived;
base->print();
// (*base).print(); // prints "Derived" !
// Base base2 = (*base);
// base2.print(); // prints "Base" !
return *base;
}
int main()
{
Base base = go();
base.print();
return 0;
}
In this case the output will be:
Derived,
COPY BASE,
Base
By returning the base object itself, you're dropping any reference to it having started off as derived and subsequently upcasted (and copied).
So effectively, what you're after will not work.
If you really "need this to return an object", I recommend a thin wrapper
struct karls_return_object {
// ... stuff ...
Base *b;
};
In the following code, the function foo is copy constructing a Base object c from a Derived object d. My question is: are we getting an exact copy? Because I'm not getting the polymorphic behavior I'm expecting
#include<iostream>
class Base
{
public:
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = new Base(*d);
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Base
}
There is no virtual constructor nor copy constructor.
However, it is possible to define a function that behaves like one.
In my case, it is the virtual member function copy() which I added to OP's sample:
#include <iostream>
class Base
{
public:
virtual Base* copy() const { return new Base(*this); }
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
virtual Base* copy() const override { return new Derived(*this); }
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = d->copy();
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Derived
return 0;
}
Output:
Hello Derived
Live Demo on coliru
The drawback is that every derived class of Base has to provide it to make it function properly. (I've no idea how to convince the compiler to check this for me with any trick.)
A partial solution could be to make copy() pure virtual in the class Base (assuming it is not meant to be instantiable).
you may wonna change the line of new
Base* c = new Derived(*d);
so you have the type Derived in a Base pointer. During runtime it is looked up, which type it is and you get the right output.
let me know if im wrong... just created this out of my mind on the fly.
To answer your question about whether or not this is copy constructing lets add some members. Base will have a member, m_b and Derived will inherit m_b but also have another member m_d
#include <iostream>
struct Base {
const int m_b;
Base() = delete;
Base(const int a_b) : m_b(a_b) {}
virtual void sayHello() {
std::cout << "Base " << m_b << std::endl;
}
};
struct Derived : public Base {
const int m_d;
Derived() = delete;
Derived(const int a_b, const int a_d) : Base(a_b), m_d(a_d) {}
void sayHello() override {
std::cout << "Derived " << m_b << ' ' << m_d << std::endl;
}
};
void foo(Derived* a) {
Base* b = new Base(*a);
b->sayHello(); // Output is "Base 1", 1 was copied from argument a
}
void bar(Derived* a) {
Base* d = new Derived(*a);
d->sayHello(); // Output is "Derived 1 2"
}
int main() {
Derived d(1, 2);
foo(&d);
bar(&d);
return 0;
}
The line:
Base* b = new Base(*a);
Created a Base and so sayHello calls Base's implementation which doesn't know about m_d. However this line does copy m_b from the derived class
The line:
Base* d = new Derived(*a);
Created a Derived and so sayHello calls Derived's implementation which copied both m_b and m_d
Expected polymorphic behavior will come into existence when the Base class pointer points to Derived class object. Then at run time the actual type of object pointed to by the Base class pointer will be checked and appropriate function will get called.
Base* c = new Base(*d); // <<-- case of object slicing
Here, c points to Base class object. Therefore, c->sayHello() ; is bound to call the Base::sayHello() at runtime.
are we getting an exact copy?. No since you are creating a Base object due to new Base. Due to object slicing the Base part of the *d object is passed to copy c'tor and what you get is corresponding Base object.
Base *c = new Derived(*d); will give the expected behavior.
The code example is just a simple mock up of my actual program which attempts to hold varying different classes all from a single base class in a base vector. Then using a virtual function call to get *this, return the derived. This way I don't need multiple containers.
#include "stdafx.h"
#include <iostream>
#include <vector>
class Base
{
public:
virtual Base* getThis() { return this; }
virtual void printClass() const { std::cout << "Base" << std::endl; }
};
class Derived : public Base
{
public:
virtual Derived* getThis() { return this; }
virtual void printClass() const { std::cout << "Derived" << std::endl; }
};
int main(int argc, _TCHAR* argv[])
{
Base Bar;
Derived Foo;
typedef std::vector<Base*> vContainer;
vContainer Objects;
Objects.push_back(new Derived);
for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
Bar = **it; // works to get Base but not wanted
// attempts
//Foo = it->getThis(); // the pointer selector doesnt work...
//Foo = static_cast<Derived>(**it); // utterly confused!
}
Bar.printClass(); // prints base as expected
//Foo.printClass(); // Mean't to print Derived
std::cin.get();
return 0;
}
I've been looking for a better understanding of this for hours now but everyone just talks about clones, which is not what I'm after.
Any help would be appreciated.
Neil
To be safe, use dynamic_cast.
for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
Bar* basePtr = *it;
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if ( derivedPtr ) // Check whether the dynamic_cast was successful.
{
// Use derivedPtr
}
}
Your code
Bar = **it; // works to get Base but not wanted
does not get object from vector to Bar. This is just assignment almost identical to this one (some output added):
class Base
{
public:
virtual Base* getThis() { return this; }
virtual void printClass() const { std::cout << "Base" << std::endl; }
Base& operator=(Base& one) { std::cout << "operator = is working" << std::endl; return *this;}
};
So, if you want to have pointer to object stored in the vector do not try to copy objects, copy pointer (*iterator).
What you're trying to achieve, which is dynamic binding of the method regardless of the static type, is the whole purpose of virtual methods. All you had to do is using pointers or references to those objects in your container.
Look at the following code:
#include <iostream>
#include <vector>
class Base
{
public:
virtual void printClass() const { std::cout << "Base" << std::endl; }
};
class Derived : public Base
{
public:
Derived(){};
virtual void printClass() const { std::cout << "Derived" << std::endl; }
};
int main()
{
typedef std::vector<Base*> vContainer;
vContainer Objects;
Objects.push_back(new Base);
Objects.push_back(new Derived);
for (vContainer::iterator it = Objects.begin(); it != Objects.end(); ++it)
{
// prints Base on 1st iteration
// prints Derived on 2nd iteration
(*it)->printClass();
}
return 0;
}
The reason why your attempt didn't work is that Bar was a local variable and not a reference/pointer. This means the size of Bar in the memory is determined at compile time and is sizeof(Base). Assigning a Derived object into it will copy the object by value and automatically delete the extra information stored in a Derived object and making it into a Base object (the extra information simply can't be stored in that amount of memory). If bar was of type Base* and you made it to point to a Derived object then Bar->printClass() would print Derived.
Hope that clarifies it.
I have an class which inherit two interfaces:
class Multi : public IFoo, public IBar {
public:
virtual ~Multi();
// Foo part
virtual void fooMethod();
// ...
// Bar part
virtual void barMethod();
// ...
};
Unfortunately this class cannot be decomposed in two separate classes for each interface. In fact in class implementation those entities (Foo and Bar) are tightly coupled, but in future they could become separate.
Another one class wants to use Multi class, having a pointer to IFoo and IBar:
class ClientClass {
public:
ClientClass(); // constructor
// smth
private:
std::shared_ptr<IFoo> foo_;
std::shared_ptr<IBar> bar_;
};
In constructor I do something like:
ClientClass::ClientClass(){
auto pMulti = new Multi;
foo_ = std::shared_ptr<IFoo>(pMulti);
bar_= std::shared_ptr<IBar>(pMulti);
}
But each of those shared pointers has separate reference counter, and it leads to deleting already deleted pointer on class destruction, am I right?
How should I treat it?
What is best practics for such case?
ClientClass::ClientClass()
{
auto pMulti = std::make_shared<Multi>();
foo_ = pMulti;
bar_ = pMulti;
}
would ensure that they have the same reference counter. You can see it for yourself:
#include <iostream>
#include <memory>
class Base1{};
class Base2{};
class Derived : public Base1, public Base2 {};
int main()
{
auto derived = std::make_shared<Derived>();
std::shared_ptr<Base1> base1 = derived;
std::shared_ptr<Base2> base2 = derived;
std::cout << "base1 usecount = " << base1.use_count() << '\n';
std::cout << "base2 usecount = " << base2.use_count() << '\n';
std::cout << "derived usecount = " << derived.use_count() << '\n';
return 0;
}
produces:
base1 usecount = 3
base2 usecount = 3
derived usecount = 3
I don't know exactly what you want to do with those pointers, but an alternative solution may be to store a std::unique_ptr<multi> multi_; and have a couple of interface functions that static cast it to plain pointers or to references:
IFoo& ClientClass::get_ifoo() {
return *(static_cast<IFoo*>(multi_.get()));
}
IBar& ClientClass::get_ibar() {
return *(static_cast<IBar*>(multi_.get()));
}
As long as you don't pass those out from the class, and don't call delete[] on them it should be quite safe.
Why does the following program crash? I have a base class whose destructor is not virtual but the child class destructor is virtual:
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::Base CTOR " << std::endl;
}
~Base() {
std::cout << "Base::Base DTOR " << std::endl;
}
};
class Child : public Base {
public:
Child(){
std::cout << "Child::Child CTOR " << std::endl;
}
virtual ~Child() {
std::cout << "Child::Child DTOR " << std::endl;
}
};
int main (int argc, char **argv) {
Base *ptr = new Child;
delete ptr;
}
What you are observing is called "undefined behavior". Make Base's dtor virtual if you want do call delete on Child instance through Base pointer.
From the 2003 standard, 5.3.5/3:
In the first alternative (delete object), if the static type of the
operand is different from its dynamic type, the static type shall be a
base class of the operand’s dynamic type and the static type shall
have a virtual destructor or the behavior is undefined.
You have undefined behavior because the static type of the pointer operand to delete does not match the dynamic type of the object that it points to and you don't meet the requirements for the exception to this rule that allows passing a pointer to a base class to the object being deleted because this exception requires the base class to have a virtual destructor.
Any behaviour is possible including the code working "as expected" or a crash.
Hope this example helps you get the point:
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::Base CTOR " << std::endl;
}
~Base() {
std::cout << "Base::Base DTOR " << std::endl;
}
private:
protected:
};
class Child : public Base {
public:
Child(){
std::cout << "Child::Child CTOR " << std::endl;
}
~Child(){
std::cout << "Child::Child DTOR " << std::endl;
}
private:
protected:
};
class gChild : public Child {
public:
gChild(){
std::cout << "Child::Child gCTOR " << std::endl;
}
~gChild(){
std::cout << "Child::Child gDTOR " << std::endl;
}
private:
protected:
};
int main ( int argc, char **argv) {
Base *ptr = new gChild;
delete ptr;
}
if virtual ~Base() ,then all destructors' print gets printed.
if virtual ~child() or virtual ~gChild(),only base destructor gets printed.
It's because the destructors executes in opposite direction.and here behaviour is undefined.You must define the base destructor virtual to get the expected result.
Thanks.
Just look at this:
#include <iostream>
class Base
{
public:
void nonvirtualmethod()
{ std::cout << "Base nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Base virtualmethod" << std::endl; }
};
class Derived: public Base
{
public:
void nonvirtualmethod()
{ std::cout << "Derived nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Derived virtualmethod" << std::endl; }
};
int main()
{
Derived d;
Derived* pd = &d;
Base* pb = &d; //< NOTE: both pd and pb point to the same object
pd->nonvirtualmethod();
pb->nonvirtualmethod();
pd->virtualmethod();
pb->virtualmethod();
}
I gives you the following output:
Derived nonvirtualmethod
Base nonvirtualmethod
Derived virtualmethod
Derived virtualmethod //< invoked by a Base*
This is because there is a difference between the static type of the pb pointer (Base*)
and the dynamic type it points to (Derived).
The difference between virtual and plain methods is that non-virtual methods follow the the static type mapping (so a Base pointer invokes Base::methods), while virtual methods follow the chain of the runtime types, hence if a Base* points to a Derived, the Derived method will be called.
Destructors, in this sense, are nothing special: if it is not virtual, a Base pointer will not invoke the Derived one, hence you are left with an half-destroyed object, that is given back to the memory store.
The reason why this is UB (and not simply denied), is because the "memory store" is not managed by the language itself, but from the platform the program is hosted in: the crash most likely depends on the fact that the missing of the Derived part (still alive) will result in the operating system trying free a block of memory with a wrong starting address.