Pointers to vectors of derived a derived class - c++

I'm trying to have a vector of pointers to vectors of differents classes and where each classes is derived from a same base class.
My code:
#include <iostream>
#include <vector>
#include <stdlib.h>
class A
{
public:
A() { std::cout << "A constructor.\n"; }
virtual ~A() { std::cout << "A destructor\n"; }
virtual void iAm() { std::cout << "I am A.\n"; }
};
class B : public A
{
public:
B() { std::cout << "B constructor.\n"; }
~B() { std::cout << "B destructor.\n"; }
virtual void iAm() { std::cout << "I am B.\n"; }
private:
std::string s;
};
class C : public A
{
public:
C() { std::cout << "C constructor.\n"; }
~C() { std::cout << "C destructor.\n"; }
virtual void iAm() { std::cout << "I am C.\n"; }
private:
std::string s;
int n;
};
int main()
{
std::vector<std::vector<A>*> vect;
vect.resize(3);
vect[0]=new std::vector<A>;
vect[1]=(std::vector<A>*) new std::vector<B>;
vect[2]=(std::vector<A>*) new std::vector<C>;
vect[0]->push_back(A());
vect[0]->push_back(A());
vect[1]->push_back(B(methods are A methods));
vect[1]->push_back(B());
vect[2]->push_back(C());
vect[2]->push_back(C());
(*vect[0])[0].iAm();
(*vect[0])[1].iAm();
(*vect[1])[0].iAm();
(*vect[1])[1].iAm();
(*vect[2])[0].iAm();
(*vect[2])[1].iAm();
}
But the execution give me:
A constructor.
A destructor.
A constructor.
A destructor.
A destructor.
A constructor.
B constructor.
B destructor.
A destructor.
A constructor.
B constructor.
A destructor.
B destructor.
A destructor.
A constructor.
C constructor.
C destructor.
A destructor.
A constructor.
C constructor.
A destructor.
C destructor.
A destructor.
I am A.
I am A.
I am A.
I am A.
I am A.
I am A.
I don't understand why, although I create B and C objects, the call of the method iAm() call the A's iAm(). The call of B and C iAm() must call the versions of B and C because the constructor are B and C and because I just cast pointers to the vectors, not the elements in the vector.
What I didn't understand about this?
Thanks You.

Your mistake is that you assume that std::vector<B> is compatible with std::vector<A> because B is derived from A. This is not the case. The inheritance relationship between A and B does not translate to an inheritance relationship between std::vector<A> and std::vector<B>. You had to use C-style casts to silence the compiler's error messages, but that doesn't fix the problem.

You might want to check out this question:
Vector that can have 3 different data types C++
Here's an example how your code could work:
std::vector<std::vector<A*>*> vect;
//you can also do vect.resize(3) and then write something like vect[0] = new std::vector<A*>;
vect.push_back(new std::vector<A*>);
vect[0]->push_back(new A());
vect.push_back(new vector<A*>);
vect[1]->push_back(new B());
(*vect[0])[0]->iAm();
(*vect[1])[0]->iAm();
This will print:
A constructor.
A constructor.
B constructor.
"I am A."
"I am B."
Also, consider using smart pointers.

Related

Virtual destructor, what would happen I didnt have a destructor in the derived class?

I've just had my lesson about virtual destructors and I have a question.
Lets say we have this code below:
#include <iostream>
class Base {
public:
virtual void fun() { std::cout << "Base Fun" << std::endl; };
virtual ~Base() { std::cout << "Base Destructor called" << std::endl; };
};
class Derived : public Base {
public:
virtual void fun() { std::cout << "Derived Fun" << std::endl; };
~Derived() { std::cout << "Derived Destructor called" << std::endl; };
};
int main()
{
Base* b = new Base();
Base* d = new Derived();
b->fun();
d->fun();
delete b;
delete d;
return 0;
}
We see that we have a Virtual destructor in our Base clase, which means when we delete d in our main, both the Base class destructor will be called and the Derived class destructor will be called..
**But what if we didnt have a destructor in our derived class, and we still wanted had the virtual destructor + we still wanted to delete d. What happens then? Does the derived class automatically "create" a destructor, and would the destructor then handle the ressource - d and delete it?
All classes have a destructor. If you don't write one explicitly, then compiler will implicitly generate it. Thus the case you are asking about "if I didn't have a destructor" doesn't exist.
and would the whole program still work as earlier?
It would work but not quite the same way since the implicitly generated destructor wouldn't print the string that your destructor prints.

Calling virtual method from virtual destructor in C++ [duplicate]

This question already has answers here:
Calling virtual method from destructor - workaround?
(4 answers)
Closed 5 years ago.
I want to destruct an object of class B.
class A {
public:
A() {
std::cout << "construct A" << av::endl;
a = new int;
}
virtual ~A() {
std::cout << "destruct A" << av::endl;
this->clear();
}
virtual void clear() {
std::cout << "clear A" << av::endl;
delete a;
}
protected:
int *a;
};
class B : public A {
public:
B() {
std::cout << "construct B" << av::endl;
b = new int;
}
~B() {
std::cout << "destruct B" << av::endl;
}
void clear() override {
std::cout << "clear B" << av::endl;
delete b;
delete this->a;
}
private:
int *b;
};
And I want it to be done with clear() method. But when I execute following code:
A *a = new B();
delete a;
I get:
construct A construct B destruct B destruct A clear A
And clear B is never printed.
What am I doing wrong?
Informally, In ~A(); the B part is already destroyed, calling any function of B doesn't make any sense.
Effective C++ Item 9: Never call virtual functions during construction or destruction.
Once a derived class destructor has run, the object’s derived class
data members assume undefined values, so C++ treats them as if they no
longer exist. Upon entry to the base class destructor, the object
becomes a base class object, and all parts of C++ — virtual functions,
dynamic_cast s, etc., —treat it that way.

Object not deleted before new is assigned

I'm kind of confused, because I was sure this should work different. Take a look at this code example:
#include <iostream>
#include <string>
using namespace std;
class base
{
public:
virtual ~base() = default;
};
class derived : public base
{
private:
int a = 0;
int *b = nullptr;
std::string lol;
public:
derived(std::string s) : b(new int(6)), lol{s} { cout << "ctor " << lol << endl; }
derived(derived const& d) : lol{d.lol + " copy"} {cout << "copy " << lol << endl; }
virtual ~derived() { cout << "dtor " << lol << endl; delete b; }
virtual void superFunction() { cout << "OMG " << lol << endl; }
};
int main()
{
derived a("a");
derived b("b");
a = b;
}
And the program output with all optimizations off is:
ctor a
ctor b
dtor b
dtor b
I was sure that in this case compiler should generate code that deletes object a and uses copy constructor to create new object. Instead it uses operator= that it implicitly declares.
Can someone explain why? Or point me to C++ standard.
Thanks.
When you write a = b;, compiler calls assignment operator, which will be automatically generated if not present in the code and not marked as deleted. Copy constructor is used only if you try to initialize a new object from another object like this:
derived a("a");
derived b = a;
Also, your code crashes before main returns as it tries to delete b, which points to the same memory from a and from b after a = b; default-assignment.
If you want to delete a with derived destructor after a = b; execution, all you need is copy-and-swap idiom. What is the copy and swap idiom? has a great answer on how to do that in legacy and modern C++. Proper implementation of rule-of-four from that answer will perfectly fit the DRY principle and help you to avoid memory issues. Note the fabulous trick with passing parameter to operator= by value, which makes compiler select the appropriate constructor (copy or move) and allows you to write only four methods instead of all five of them.

Usage of Derived class with the std::shared_ptr of Base class

Is the following approach good?
class TA { };
class TB : TA { };
std::shared_ptr<TA> spta;
spta.reset(new TB);
There's one problem with the code shown, TB must inherit publicly from TA. You have a shared_ptr<TA>, so the pointer you want to store in it must be convertible to TA, but with private inheritance, the base is inaccessible so your code will not compile.
class TA { };
class TB : public TA { };
Beyond this, the code has no errors and is well-behaved. Typically, when you perform polymorphic deletion of a derived class instance through a base class pointer, you need the base class' destructor to be virtual so the derived class destructor is called, but in case of shared_ptr this is not necessary. shared_ptr::reset is a function template that'll accept any Y* that is convertible to the managed pointer type. The same is true for shared_ptr's constructor template.
That being said, you should prefer making the base class' destructor virtual, especially if the classes involved have other virtual functions.
No, it is not for TA is private.
Moreover, as suggested in the comments, the destructor of the base class ought to be virtual. It is usually a good practice, for you cannot guarantee that instances of your classes will be used only with shared pointers.
To have it working, you must at least modify these lines:
class TA { };
class TB : TA { };
As it follows:
class TA { virtual ~TA() { } };
class TB : public TA { };
Those ones are good as the following example is good:
class TA { virtual ~TA() { } };
class TB : public TA { };
TA *spta = nullptr;
spta = new TB;
It mainly depends on what good means for you. It's legal, at least.
This is not an answer to the question, it is an attempt to clear up any confusion about shared_ptr's seemingly magical ability to avoid the use of a virtual destructor.
Here's a little demo program:
#include <iostream>
#include <memory>
struct A {
~A() { std::cout << __func__ << std::endl; }
void foo() { do_foo(); }
protected:
virtual void do_foo() {
std::cout << "A::" << __func__ << std::endl;
}
};
struct B : A {
~B() { std::cout << __func__ << std::endl; }
virtual void do_foo() override {
std::cout << "B::" << __func__ << " ";
A::do_foo();
}
};
using namespace std;
auto main() -> int
{
std::shared_ptr<A> p = std::make_shared<A>();
p->foo();
p = std::make_unique<B>();
p->foo();
cout << "deleting B:" << endl;
return 0;
}
expected output:
A::do_foo
~A
B::do_foo A::do_foo
deleting B:
~B
~A
Notice that the correct destructor was called when the B was destroyed at the end of main().

default virtual d'tor

Let us assume I have two classes:
class Base{};
class Derived: public Base{};
none has d'tor, in this case if I declare about variables:
Base b;
Derived d;
my compiler will produce for me d'tors, my question is, the default d'tors of the b and d will be virtual or not?
my question is, the d'tors of the b and d will be virtual or not
No, they won't. If you want a virtual destructor, you will have to define your own, even if its implementation is exactly the same as that which would be supplied by the compiler:
class Base {
public:
virtual ~Base() {}
};
The destructors of Base and Derived will not be virtual. To make a virtual destructor you need to mark it up explicitly:
struct Base
{
virtual ~Base() {}
};
Actually there's now only one reason to use virtual destructors. That is to shut up the gcc warning: "class 'Base' has virtual functions but non-virtual destructor". As long as you always store your allocated objects in a shared_ptr, then you really don't need a virtual destructor. Here's how:
#include <iostream> // cout, endl
#include <memory> // shared_ptr
#include <string> // string
struct Base
{
virtual std::string GetName() const = 0;
};
class Concrete : public Base
{
std::string GetName() const
{
return "Concrete";
}
};
int main()
{
std::shared_ptr<Base> b(new Concrete);
std::cout << b->GetName() << std::endl;
}
The shared_ptr will clean up correctly, without the need for a virtual destructor. Remember, you will need to use the shared_ptr though!
Good luck!
my question is, the d'tors of the b and d will be virtual or not
Short answer : Nopes!
They will NOT be virtual.However, if you declared(and defined) a virtual dtor in Base, then the derived's dtor would be automatically virtual. HTH.
How can they be virtual unless you explicitly make them as virtual
Just to add one more example to Daniel Lidström's answer
As long as you always store your allocated objects in a shared_ptr, then you really don't need a virtual destructor.
If one uses a shared_ptr like this:
std::shared_ptr<Base> b(new Concrete);
Then the Concrete destructor and the Base destructor are called on destruction of the object.
If one uses a shared_ptr like this:
Base* pBase = new Concrete;
std::shared_ptr<Base> b(pBase);
Then only the Base destructor is called on destruction of the object.
This is an example
#include <iostream> // cout, endl
#include <memory> // shared_ptr
#include <string> // string
struct Base
{
virtual std::string GetName() const = 0;
~Base() { std::cout << "~Base\n"; }
};
struct Concrete : public Base
{
std::string GetName() const
{
return "Concrete";
}
~Concrete() { std::cout << "~Concrete\n"; }
};
int main()
{
{
std::cout << "test 1\n";
std::shared_ptr<Base> b(new Concrete);
std::cout << b->GetName() << std::endl;
}
{
std::cout << "test 2\n";
Base* pBase = new Concrete;
std::shared_ptr<Base> b(pBase);
std::cout << b->GetName() << std::endl;
}
}