C ++ unique_ptr приведение от производной к базовой - PullRequest
0 голосов
/ 16 февраля 2019

Я читаю и пытаюсь понять и заставить это работать.

У меня есть базовый класс Person, от которого унаследованы Учитель и Студент.Я хочу хранить их оба внутри вектора типа «Персона».Я попробовал несколько вещей.Тем не менее, я продолжаю получать страницы ошибок, и я изо всех сил пытаюсь понять их.

Этот текущий код, скомпилированный с g ++ -std = c ++ 17 test.cpp, дает мне:

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

Буду признателен за любые советы и полезные ссылки на функции c ++, написанные просто.

#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;
}

Редактировать: я получил его, изменив деструктор базового класса на значение по умолчанию.

Теперь у меня есть это:

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();
}

, но я получаю следующую ошибку:

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

edit 2:

При использовании выше:

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

Может кто-нибудь объяснить мне?Вектор содержит уникальные указатели (которые когда-то были rvalue (в частности, exrvalue), но теперь это не так. Почему мне нужно использовать auto &&?

1 Ответ

0 голосов
/ 16 февраля 2019

Я очистил код и попытаюсь объяснить изменения.

#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;
}
...