问题
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