0

I have been reading around and am struggling to understand and get this working.

I have a base class Person, which Teacher & Student inherit from. I want to store them both inside of a vector of type "Person". I have tried a few things. However, I keep getting pages of errors, and I am struggling to understand them.

This current code compiled with g++ -std=c++17 test.cpp is giving me:

Undefined symbols for architecture x86_64: "Person::~Person()", referenced from: Teacher::~Teacher() in test-9423bf.o Student::~Student() in test-9423bf.o ld: symbol(s) not found for architecture x86_64 

Would appreciate any tips and good references on c++ features written simply.

#include <iostream> #include <vector> #include <memory> class Person { public: virtual void printName() = 0; virtual ~Person() = 0; }; class Teacher : public Person { public: void printName() { std::cout << "Hello My Name is Teacher" << std::endl; } ~Teacher() {} }; class Student : public Person { public: void printName() { std::cout << "Hello My Name Is Student" << std::endl; } ~Student() {} }; //Capturing the raw pointer and letting it go out of scope template<typename Person, typename Teacher> std::unique_ptr<Person> static_unique_pointer_cast (std::unique_ptr<Teacher>&& old){ return std::unique_ptr<Person>{static_cast<Person*>(old.release())}; //conversion: unique_ptr<FROM>->FROM*->TO*->unique_ptr<TO> } auto main() -> int { auto t1 = std::make_unique<Teacher>(); auto t2 = std::make_unique<Teacher>(); auto t3 = std::make_unique<Teacher>(); auto s1 = std::make_unique<Student>(); auto s2 = std::make_unique<Student>(); auto s3 = std::make_unique<Student>(); std::vector<std::unique_ptr<Person>> v; // v.push_back(static_unique_pointer_cast<Person>(std::move(s1))); auto foo = static_unique_pointer_cast<Person>(std::move(s1)); // std::vector<std::unique_ptr<Person>> ve = { // std::move(t1), // std::move(t2), // std::move(t3), // std::move(s1), // std::move(s2), // std::move(s3) // }; return 0; } 

Edit: I got it working by changing base class destructor to default.

I now have this:

std::vector<std::unique_ptr<Person>> v; v.push_back(static_unique_pointer_cast<Person>(std::move(s1))); v.push_back(static_unique_pointer_cast<Person>(std::move(s1))); for (auto item: v) { item->printName(); } 

but I am getting the following error:

error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<Person, std::__1::default_delete<Person> >' for (auto item: v) { 

edit 2:

The above works when I use:

for (auto &&item: v) { item->printName(); } 

Could someone explain this to me? The vector holds unique pointers (that were once an rvalue (specifically exrvalue) but now they aren't. Why do I need to use auto &&?

3
  • 5
    Derived types' destructors will try to call the base type's destructor. Don't make it pure virtual. Use = default instead of = 0;. Commented Feb 15, 2019 at 22:19
  • 2
    Or provide an out-of-class definition for your pure virtual destructor. Commented Feb 15, 2019 at 22:24
  • 3
    You can't copy unique_ptr's which is what it tries to do with 'for (auto item: v)'. better to use a const ref like ''for (const auto& item: v) Commented Feb 15, 2019 at 22:34

1 Answer 1

3

I've cleaned up the code an will try to explain the changes.

#include <iostream> #include <vector> #include <memory> class Person { public: virtual ~Person() = default; // before this was a pure-virtual d'tor. Usually, you don't need it, but the linker told you it wasn't implemented virtual void printName() = 0; }; class Teacher : public Person { public: void printName() override { std::cout << "Hello My Name is Teacher\n"; } // removed d'tor since you already have a default virtual destructor here }; class Student : public Person { public: void printName() override { std::cout << "Hello My Name Is Student\n"; } // removed d'tor since you already have a default virtual destructor here }; // removed template this upcasting is almost straight forward. auto main() -> int { auto t1 = std::make_unique<Teacher>(); auto t2 = std::make_unique<Teacher>(); auto t3 = std::make_unique<Teacher>(); auto s1 = std::make_unique<Student>(); auto s2 = std::make_unique<Student>(); auto s3 = std::make_unique<Student>(); std::vector<std::unique_ptr<Person>> v; v.push_back(std::move(t1)); v.push_back(std::move(t2)); v.push_back(std::move(t3)); // Easy to add Students and Teachers v.push_back(std::move(s1)); v.push_back(std::move(s2)); v.push_back(std::move(s3)); for (auto &item: v) { // Taking a reference, `&`, the pointers in `v` still stay there after the loop and can be reused. Don't use `&&` unless you want the use the pointers once only. item->printName(); } return 0; } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.