0

Iā€˜m trying to understand a C++ code that uses vector which stores unique_ptr<Base>, where Base is a base class and has a derived class Derivate.

When pushing unique_ptr<Derivate> into this vector, there is no errors and can correctly call the method of derived class.

But when trying to modify a specific attribute of Derivate, there is an error " error: 'class Base' has no member named 'deri_name' ".

The code is as follow:

#include<iostream>
#include<vector>
#include <memory>
using namespace std;

class Base
{
public:
    virtual void test(){
        cout << "this is Base test" << endl;
    }

};

class Derivate :public Base
{
public:
    Derivate(const string& name):deri_name(name){

    }
    virtual void test(){
        cout << "this is Derivate test by " << deri_name << endl;
    }

    string deri_name;
};

int main()
{
    vector<unique_ptr<Base>> vec;
    vec.push_back(make_unique<Derivate>("wayne"));

    vec[0]->test(); // will sprint "this is Derivate test by wayne"

    //vec[0]->deri_name = 'wong';  // will report an error " error: 'class Base' has no member named 'deri_name' "

    return 0;
}

I've tried some methods, but there seems no straightforward way to cast vec[0] from unique_ptr<Base> to unique_ptr<Derivate>

could I possibly modify vec[0]->deri_name without modifying the type of vec?

  • Given that a `unique_ptr` may not actually be managing a `Derivate` (in which case, forcing the compiler to allow you to act as if it is will cause undefined behaviour) why do you want to do this? As a rough rule, unless you have a VERY specific reason, a need/desire to do something like this is usually a sign of a broken design, and it is better to fix the design instead of trying to force the compiler to allow you to do this. – Peter Apr 12 '23 at 03:49
  • "*there seems no straightforward way to cast `vec[0]` from `unique_ptr` to `unique_ptr`*" - you can't cast a `unique_ptr` to a `unique_ptr` when `X != Y` under any circumstance, as they are completely unrelated types. You can, however, move-construct a `unique_ptr` from a `unique_ptr` if `Y` derives from `X`, and cast a raw `X*` to a raw `Y*` if `Y` derives from `X` or vice versa. – Remy Lebeau Apr 12 '23 at 03:54

1 Answers1

3

The vector stores pointers to Base, which has no member named deri_name. If you are certain that vec[0] points to a Derivate object, you can static-cast:

static_cast<Derivate&>(*vec[0]).deri_name = "wong";

If you don't know for sure, you can dynamic-cast:

if (auto ptr = dynamic_cast<Derivate*>(vec[0].get()))
    ptr->deri_name = "wong";

Because this kind of thing is typically a pain, consider making your Base class provide virtual methods for operations that derivative classes can opt into. For instance, a set_name method that by default does nothing, but the Derivate class overrides.

Only you know your requirements, but it's often worth considering ways to avoid polluting code with typecasts, if you can cleanly implement something without it.

paddy
  • 60,864
  • 6
  • 61
  • 103