How to return derived type?

ぃ、小莉子 提交于 2019-12-12 18:27:18

问题


I have a Validator class and derived classes from it; When i'm trying to return pointer to derived class then method return base class(Validator) instead of Derived.

class Validator
{
public:
    std::string m_name = "BaseValidator";

    static const std::map<std::string, Validator *> validators();

    static Validator *getByName(std::string &name);
};


const std::map<std::string, Validator*> Validator::validators()
{
    std::map<std::string, Validator*> result;
    //RequiredValidator is derived
    result["required"] = new RequiredValidator();
    return result;
}

Validator* Validator::getByName(std::string &name)
{
    auto g_validators = Validator::validators();
    auto validator = g_validators.find(name);
    if(validator != g_validators.end()){
        std::cout << "getByName: " << validator->second->m_name << std::endl;
        return validator->second;
    }else{
        std::cerr << "Unknow type of validator: " << name << std::endl;
    }
    return nullptr;
}

//output BaseValidator but i need RequiredValidator


class RequiredValidator : public Validator
{
public:
    std::string m_name = "RequiredValidator";
};

回答1:


It is returning a derived instance, but since validator is a Validator*, you're looking at the m_name member of Validator, not the one of RequiredValidator.
(Despite having the same name, they are distinct variables. There are no "virtual variables".)

There are a couple of options;

  • You can have a virtual getName function and override it in every subclass.

  • Set the base m_name in derived classes, for instance by making the name a parameter of the base constructor.

Example:

class Validator
{
public:
    Validator(const std::string& name = "BaseValidator") : m_name(name) {};
    // ...
};

class RequiredValidator : public Validator
{
public:
    RequiredValidator() : Validator("RequiredValidator") {}
    // ...
};



回答2:


You have declared two member variables named m_name, one in Validator and one in RequiredValidator. Other than having the same name these two variables are completely unrelated. Your compiler will probably have printed a warning about the second shadowing the first.

Which variable you access depends on the type of the variable that you are accessing it from.

For example:

RequiredValidator r;
std::cout << r.m_name << "\n"; // prints "RequiredValidator"
Validator* v = &r;
std::cout << v->m_name << "\n"; // prints "BaseValidator"
std::cout << dynamic_cast<RequiredValidator*>(v)->m_name << "\n"; // prints "RequiredValidator"

There are a couple of solutions to this. The first is to simply set the value of the BaseValidator variable in the RequiredValidator constructor:

class Validator
{
public:
   std::string m_name;
   Validator( const std::string& name = "BaseValidator" )
   :m_name( name )
   {
   }
};

class RequiredValidator : public Valdiator
{
public:
    RequiredValidator()
    : Validator("RequiredValidator")
    {}
};

The more conventional solution would be to use a virtual method instead:

class Validator
{
public:
  virtual std::string getName() { return "BaseValidator"; }
};

class RequiredValidator : public Valdiator
{
public:
  virtual std::string getName() override { return "RequiredValidator"; }
};


来源:https://stackoverflow.com/questions/54194395/how-to-return-derived-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!