Как вернуть объект класса, который является производным от абстрактного класса? - PullRequest
0 голосов
/ 21 мая 2019

Итак, у меня есть универсальный оператор.В этом конкретном случае его общий шаблон T должен быть указателем на абстрактный базовый класс.Дело в том, что когда я создаю T *t и пытаюсь вернуть *t, я получаю сообщение об ошибке, говорящее о том, что T невозможно создать, потому что это абстрактный класс.Даже если *t всегда будет объектом производных классов, которые не являются абстрактными.Он не принимает это, потому что T в конце концов абстрактный тип.По сути, я хочу получить ссылку на *t, возвращаемую из operator в main(), а затем присвоить ей объекты производных классов в main().

Я понимаю, чтоЕсть вопросы по нарезке и полиморфизму.Но я пытаюсь понять, как я могу достичь этого по-разному.Это совершенно другой вопрос, который касается следующего конкретного кода.

Код выглядит примерно так:

Template <class T>
class myArr{
T & operator [] (int index){
T*t;
Arr[0] = *t;
Return arr[0[;

 }}

Main(){
Base * b=new derived;
myArr<Base>[17]=*b;

// Point is, I can make it of type pointers and maybe it can 
//work but I prefer assigning *b to myArr because I want 
to //assign objects themselves

}

У меня вопрос, как я могу вернуть сам объект из * 1017?*?Я хочу вернуть то, что я могу назначить производный объект.Я пытаюсь сделать это с указателем типа абстрактной базы, чтобы достичь полиморфизма, чтобы он мог содержать любой объект производных классов.

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Вы не можете вернуть объект абстрактного класса.Вам необходимо вернуть ссылку или указатель , предпочтительно умный.

Вы не можете хранить объект абстрактного класса.Вам необходимо сохранить ссылку или указатель , предпочтительно умный.

Вы не можете передать объект абстрактного класса вфункция в качестве параметра.Вам нужно передать ссылку или указатель , предпочтительно умный.

См. Шаблон?

Объекты абстрактных классов не существуютсамостоятельно.Они существуют только как подобъекты объектов производного класса и доступны только через ссылки или указатели, полученные из указателей на указанные объекты производного класса.

Обойти это невозможно.Вы не можете сделать это по-другому.Используйте умные указатели.Они являются подходящим инструментом для этой работы.

Я хочу вернуть что-то, на что я могу назначить производный объект.

Это возможно, в зависимости от того, что именно вы хотите, но гораздо сложнее, чем необходимо.Назначение и полиморфные иерархии плохо сочетаются.Я бы не советовал, особенно если вы не уверены, что именно вы хотите.Назначайте, храните и передавайте умные указатели.

0 голосов
/ 21 мая 2019

Я попытался сделать что-то из кода, который вы показали, используя std::unique_ptr<Base> в вашем массиве. В нем показано, как можно заменить объекты в массиве (base_arr[0] = ...) и как обновить существующие объекты в массиве (*base_arr[0] = ...). Я добавил два производных класса, несущих разные типы (std::string и int) и множество отладочных отпечатков, чтобы было легче следить за тем, что происходит, когда вы его запускаете.

#include <iostream>
#include <vector>
#include <memory>
#include <string>

// Your container wrapper with some functions
template<class T>
class myArr {
public:
    using type = T;
    template<class... Args>
    decltype(auto) emplace_back(Args&&... args) {
        return arr.emplace_back(std::forward<Args>(args)...);
    }

    T& operator[](std::size_t index) { return arr[index]; }
    auto begin() const { return arr.begin(); }
    auto end() const { return arr.end(); }
    T extract_front() {
        T retval(std::move(arr.front()));
        arr.erase(arr.begin());
        return retval;
    }

private:
    std::vector<T> arr{};
};
//----------------------------------------------------------------------------------
struct Base {
    Base() = default;
    Base(const Base&) = default;
    Base(Base&&) = default;
    virtual ~Base() = 0;
    virtual Base& operator=(const Base&) = 0;
    virtual Base& operator=(Base&&) = 0;
    virtual void print() = 0;
};

Base::~Base() {}

Base& Base::operator=(const Base&) {
    std::cout << "Base& Base::operator=(const Base&)\n"; // nothing real to copy here
    return *this;
}

Base& Base::operator=(Base&&) {
    std::cout << "Base& Base::operator=(Base&&)\n"; // nothing real to move here
    return *this;
}
//----------------------------------------------------------------------------------
struct der_1 : public Base {
    der_1(const std::string& value) : Base(), m_value(value) {
        std::cout << "der_1(" << m_value << ") converting\n";
    }
    der_1(const der_1& rhs) : Base(rhs), m_value(rhs.m_value) {
        std::cout << "der_1(" << m_value << ") copy\n";
    }
    der_1(der_1&& rhs) : Base(std::move(rhs)), m_value(std::move(rhs.m_value)) {
        std::cout << "der_1(" << m_value << ") move\n";
    }
    ~der_1() { std::cout << "~der_1(" << m_value << ")\n"; }

    der_1& operator=(const der_1& rhs) {
        std::cout << "der_1& der_1::operator=(const der_1&)\n";
        if(this == &rhs) return *this; // no self-assignment
        Base::operator=(rhs);          // copy the Base part of rhs
        m_value = rhs.m_value;         // copy the der_1 specific part
        return *this;
    }

    der_1& operator=(der_1&& rhs) {
        std::cout << "der_1& der_1::operator=(der_1&&)\n";
        Base::operator=(std::move(rhs));  // move the Base part of rhs
        m_value = std::move(rhs.m_value); // move the der_1 specific part
        return *this;
    }

    // override Base's copy assignment
    Base& operator=(const Base& rhs) override {
        std::cout << "Base& der_1::operator=(const Base&)\n";
        // downcasting may throw bad_cast
        const der_1& rhsref = dynamic_cast<const der_1&>(rhs);
        return *this = rhsref; // call standard copy assignment
    }

    // override Base's move assignment
    Base& operator=(Base&& rhs) override {
        std::cout << "Base& der_1::operator=(Base&&)\n";
        // downcasting may throw bad_cast
        der_1& rhsref = dynamic_cast<der_1&>(rhs);
        return *this = std::move(rhsref); // call standard move assignment
    }

    void print() override { std::cout << "der_1::print(" << m_value << ")\n"; }

private:
    std::string m_value;
};
//----------------------------------------------------------------------------------
struct der_2 : public Base {
    der_2(int value) : Base(), m_value(value) {
        std::cout << "der_2(" << m_value << ") converting\n";
    }
    der_2(const der_2& rhs) : Base(rhs), m_value(rhs.m_value) {
        std::cout << "der_2(" << m_value << ") copy\n";
    }
    der_2(der_2&& rhs) : Base(std::move(rhs)), m_value(std::move(rhs.m_value)) {
        std::cout << "der_2(" << m_value << ") move\n";
    }
    ~der_2() { std::cout << "~der_2(" << m_value << ")\n"; }

    der_2& operator=(const der_2& rhs) {
        std::cout << "der_2& der_2::operator=(const der_2&)\n";
        if(this == &rhs) return *this; // no self-assignment
        Base::operator=(rhs);          // copy the Base part of rhs
        m_value = rhs.m_value;         // copy the der_2 specific part
        return *this;
    }

    der_2& operator=(der_2&& rhs) {
        std::cout << "der_2& der_2::operator=(der_2&&)\n";
        Base::operator=(std::move(rhs));  // move the Base part of rhs
        m_value = std::move(rhs.m_value); // move the der_2 specific part
        return *this;
    }

    // override Base's copy assignment
    Base& operator=(const Base& rhs) override {
        std::cout << "Base& der_2::operator=(const Base&)\n";
        // downcasting may throw bad_cast
        const der_2& rhsref = dynamic_cast<const der_2&>(rhs);
        return *this = rhsref; // call standard copy assignment
    }

    // override Base's move assignment
    Base& operator=(Base&& rhs) override {
        std::cout << "Base& der_2::operator=(Base&&)\n";
        // downcasting may throw bad_cast
        der_2& rhsref = dynamic_cast<der_2&>(rhs);
        return *this = std::move(rhsref); // call standard move assignment
    }

    void print() override { std::cout << "der_2::print(" << m_value << ")\n"; }

private:
    int m_value;
};
//----------------------------------------------------------------------------------
int main() {
    myArr<std::unique_ptr<Base>> base_arr;
    {
        {
            std::cout << "-- put pointers to objects of derived classes in base_arr --\n";
            base_arr.emplace_back(std::make_unique<der_1>("howdy"));
            base_arr.emplace_back(std::make_unique<der_2>(10));

            std::cout << "\n-- print what we've got --\n";
            for(auto& b : base_arr) b->print();

            std::cout << "\n-- set new value for an existing object, by copying --\n";
            der_1 something_to_copy("something_to_copy");
            *base_arr[0] = something_to_copy;

            std::cout << "\n-- set new value for an existing object, by moving --\n";
            *base_arr[0] = der_1("something_to_move");

            std::cout << "\n-- try to assign a der_2 to a der_1 --\n";
            try {
                *base_arr[0] = der_2(666);
            } catch(const std::exception& ex) {
                std::cout << "Exception: " << ex.what() << "\n";
            }

            std::cout << "\n-- replace a der_1 object with a der_2 object --\n";
            base_arr[0] = std::make_unique<der_2>(20);

            std::cout << "\n-- destroying something_to_copy since it goes out of "
                         "scope --\n";
        }
        std::cout << "\n-- stuff in base_arr --\n";
        for(auto& b : base_arr) b->print();

        std::cout << "\n-- extract front, got:\n";
        auto ptr = base_arr.extract_front();
        ptr->print();
        std::cout << "\n-- the above dies, goes out of scope --\n";
    }

    std::cout << "\n-- base_arr is about to be destroyed --\n";
}
...