如何返回派生自抽象类的类的对象?

时间:2019-05-21 04:30:50

标签: c++ polymorphism abstract-data-type

所以,我有一个通用运算符。在这种特定情况下,其通用模板T应该是指向抽象基类的指针。关键是,当我创建T *t并尝试返回*t时,我收到一条错误消息,指出T不能被实例化,因为它是一个抽象类。即使*t始终是不是抽象的派生类的对象。它不接受它,因为T毕竟是抽象类型。基本上,我要实现的是获得对从*t返回到operator的{​​{1}}的引用,然后为其分配main()中派生类的对象。 / p>

我了解到有关切片和多态性的问题。但是我试图了解如何以不同的方式实现它。这是一个完全不同的问题,涉及以下特定代码。

代码是这样的:

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 } 返回对象本身?我想返回可以分配派生对象的对象。我正在尝试使用abstract base类型的指针来实现它,以实现多态性,以便它可以包含派生类的任何对象。

2 个答案:

答案 0 :(得分:1)

您不能返回抽象类的 object 。您需要返回一个引用指针,最好是一个聪明的指针。

您不能存储抽象类的对象。您需要存储一个引用指针,最好是一个聪明的指针。

您不能将抽象类的 object 作为参数传递给函数。您需要传递一个 reference 或一个 pointer ,最好是一个聪明的指针。

看到图案了吗?

抽象类的对象本身并不存在。它们仅作为派生类对象的子对象存在,并且只能通过从指向所述派生类对象的指针获得的引用或指针进行访问。

没有办法解决。您不能做不同的事情。使用智能指针。它们是完成这项工作的正确工具。

  

我想返回一些可以分配派生对象的对象。

这是可能的,具体取决于您想要的是什么,但是方法比必要的复杂。分配和多态层次结构不能很好地融合在一起。我不建议这样做,特别是如果您不确定确切要什么时。分配,存储和传递智能指针。

答案 1 :(得分:0)

我尝试通过在数组中使用std::unique_ptr<Base>从您显示的代码中做出一些事情。它显示了如何替换数组(base_arr[0] = ...)中的对象以及如何更新数组中的现有对象(*base_arr[0] = ...)。我添加了两个派生类,它们带有不同的类型(std::stringint)和大量的调试打印信息,因此在运行它时可以更轻松地跟踪正在发生的事情。

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