0

So, I have a generic operator. In this specific case its generic template T is supposed to be a pointer to an abstract base class. The point is, when I create T *t and try to return *t I get an error saying T can't be instantiated because it's an abstract class. Even though *t will always be an object of derived classes which aren't abstract. It doesn't accept it, because T is after all abstract type. Basically, what I want to achieve is to get a reference to the *t returned from the operator to main() and then assign to it objects of derived classes in main().

I understand that there are questions about slicing and polymorphism. But I am trying to understand how can I achieve it in different ways. It's a completely different question which deals with the following specific code.

Code is something like this:

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

}

My question is, how can I return the object in itself from the operator? I want to return something to which I can assign a derived object . I am trying to do it with pointer of type abstract base, so as to achieve polymorphism so it can contain any object of derived classes.

Barushkish
  • 69
  • 2
  • 9
  • 1
    Could you show the code that gives you the error? I suspect you are [slicing objects](https://stackoverflow.com/questions/274626/what-is-object-slicing). In short, you can't return `T` by value. You could perhaps return a `std::unique_ptr`, but again, some code examples that illustrate what you're trying to achieve would be nice. – alter_igel May 21 '19 at 04:39
  • *"`*t` will always be an object of derived classes "* - not true. Like it or not, `*t` is type `T`. Period. you're effectively *slicing*. If you want to do this you need a dynamic vehicle, by pointer or reference; a smart version of the former would likely be high on probability. – WhozCraig May 21 '19 at 04:40
  • So how do I achieve it. Can you be more specific? I don't understand. I want the operator to return a reffernce type of the derived object itself. – Barushkish May 21 '19 at 04:44
  • 2
    *"I want the operator to return a reference type"* - What operator? Update your question to show a [mcve] exhibiting what you're trying (and failing) to do. – WhozCraig May 21 '19 at 04:53
  • I edited it. Can you look over it again? – Barushkish May 21 '19 at 05:00
  • You can't have an array of the abstract type either. – molbdnilo May 21 '19 at 05:03
  • Of course I can. It has no problem with it. It isn't an array, it's a generic class – Barushkish May 21 '19 at 05:06
  • 2
    Please show code that doesn't have obvious errors like undeclared identifiers, `[0[` and stuff like that. It is pretty hard to judge your intent from something a piece if code doesn't make sense. – n. m. could be an AI May 21 '19 at 05:12
  • 2
    Even after your edit, this isn't a complete example. Make it possible to compile the code. Btw, having a class name `basè` and another named `Base` is one way to confuse people trying to help. – Ted Lyngmo May 21 '19 at 05:15

2 Answers2

1

You cannot return an object of an abstract class. You need to return a reference or a pointer, preferably a smart one.

You cannot store an object of an abstract class. You need to store a reference or a pointer, preferably a smart one.

You cannot pass an object of an abstract class to a function as a parameter. You need to pass a reference or a pointer, preferably a smart one.

See the pattern?

Objects of abstract classes do not exist on their own. They only exist as subobjects of derived class objects, and can only be accessed via references or pointers obtained from pointers to said derived class objects.

There is no way around it. You cannot do it differently. Use smart pointers. They are the right tool for tthe job.

I want to return something to which I can assign a derived object .

This is kind of possible, depending on what exactly you want, but way more complicated than necessary. Assignment and polymorphic hierarchies don't mix well. I would not recommend that, especially if you are not sure what exactly you want. Assign, store, and pass around smart pointers.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • But that's all point I am not trying to make an object of an a bstract class. All I am looking for is , for the operator to return a reference type object of the derived class so that I could assign to it in main – Barushkish May 21 '19 at 05:53
  • If you want a reference to a *derived* class, just do that. Why involve a base class? A reference to a *base* class will not work, it will result in object slicing and this is not what you want. There are ways around it but they are problematic and not worth it. It is not recommended to assign and pass around objects in polymorphic hierarchies. Assign and pass around smart pointers. – n. m. could be an AI May 21 '19 at 06:21
  • Because I want to assign object types instead of pointers to my array. On the other hand I need the operator to return a reference to the object so that I simply assign to it in main like a regular array. And you ask why I don't just return the object of derived it's because I want to allow all objects of all derived classes not just a specific type of one derived class – Barushkish May 21 '19 at 06:31
  • "I want to assign object types instead of pointers to my array" Why? This is not going to work well, it will be needlessly complicated, and you will regret it. Don't do that unless you know exactly why you are doing this and why storing and assigning pointers doesn't meet your needs. – n. m. could be an AI May 21 '19 at 07:03
  • I recommend forgetting temporary about `myArray` or whatever it's called, and concentrate on the references themselves. `Derived1 d1; Derived2 d2; Base& b = d1; b = d2;` What do you want to happen when you write this? If you can answer this question, then it is trivial to wrap `b` in whatever generic class you want. If you cannot, then no amount of wrapping will help you. – n. m. could be an AI May 21 '19 at 07:15
  • What I want? I want all of those types to be able to be assigned to the same customed array. – Barushkish May 21 '19 at 07:39
  • But by "assigned" I mean and prefer it to be like simple array. Arr[5]=d1 – Barushkish May 21 '19 at 07:41
  • So this can be achieved only if I return reffernce to object – Barushkish May 21 '19 at 07:42
  • You can't. An array stores a single object type. In your case there is not much choice. Your array needs to store pointers to the base class one way or another. Once you accept that your array stores pointers, it is an inevitable conclusion that whenever you assign an element of the array, you assign a pointer. You cannot assign a pointed-to object. Oh and you are still not saying *why* you want it. Why not explain that clearly? Whimsical desires have no place in software development. Demostrate the need. – n. m. could be an AI May 21 '19 at 07:52
  • "So this can be achieved only if I return reffernce to object" nope, try again. – n. m. could be an AI May 21 '19 at 07:53
0

I tried making something out of the code you showed by using std::unique_ptr<Base> in your array. It shows how you can replace objects in the array (base_arr[0] = ...) and how to update existing objects in the array (*base_arr[0] = ...). I added two derived classes carrying different types (a std::string and an int) and a lot of debug prints so it's easier to follow what's happening when you run it.

#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";
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • I want my own custtomed array to be assigned values like regular array. maArr arrr[5]= some; – Barushkish May 21 '19 at 06:58
  • Also, I want to be able to assign any type of derived class object in the same array – Barushkish May 21 '19 at 07:03
  • @Barushkish C++ doesn't support arrays with elements of different types. All array elements must have the same type. Your needs cannot change that. – Daniel Langr May 21 '19 at 08:13
  • @Barushkish but you come close with the above. You can assign a slot an object of any type based on Base and assign new values to existing objects. – Ted Lyngmo May 21 '19 at 08:45
  • @Barushkish I added some more to give one example how you can come close to what you want to do. You may also want to look at `std::any` and `std::variant`. – Ted Lyngmo May 21 '19 at 16:34