C++ 如何调用精确的派生类方法?

C++ 如何调用精确的派生类方法?,c++,polymorphism,C++,Polymorphism,继续我先前的问题: 我有一个验证器类和它的派生类;当我努力的时候 若要返回指向派生类的指针,则方法返回base 类验证器,而不是派生的 我将我的类修改为下一个: class Validator { public: std::string m_name = "BaseValidator"; static const std::map<std::string, Validator *> validators(); void validateModel(Mod

继续我先前的问题:

我有一个验证器类和它的派生类;当我努力的时候 若要返回指向派生类的指针,则方法返回base 类验证器,而不是派生的

我将我的类修改为下一个:

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

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

    void validateModel(Model &model, const std::vector<std::string> &attrNames);
    static Validator *getByName(std::string &name);

    virtual void validateAttribute(Model &model, const std::string &attribute);
    virtual ~Validator();

    virtual std::string name() const;
};

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

void Validator::validateModel(Model &model, const std::vector<std::string> &attrNames)
{      
     validateAttribute(model, name.at(0));    
}

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

void Validator::validateAttribute(Model &model, const std::string &attribute)
{
    (void)model;
    (void)attribute;
    std::cout << this->name() << std::endl;
}

//------------------

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

    void validateAttribute(Model &model, std::string &attribute);
    ~RequiredValidator();
    std::string name() const;
};


std::string RequiredValidator::name() const
{
    return m_name;
}

void RequiredValidator::validateAttribute(Model &model, std::string &attribute)
{
    (void) model;
    (void) attribute;
    std::cout << "RequiredValidator!!!" << std::endl;
}

RequiredValidator::~RequiredValidator()
{

}


//------------------

auto validator = Validator::getByName("required");

validator->name();// will output RequiredValidator

//next i'm calling 

validator->validateModel(); // whos calling validateAttribute() inside
//and it's output Validator::validateAttribute() //but i wan't
//RequiredValidator::validateAttribute(); 
//where i was wrong with logic???
与我希望的虚拟方法名称相同,但是 validateAttribute仅从基类调用


仔细查看如何定义void RequiredValidator::validateAttribute

您可能会注意到签名与基本std::string稍有不同&属性不是常量

有一个关键字覆盖可以帮助编译器捕获这些类型的输入错误

首先,正如其他人所指出的, §13.1标准中讨论了不能 过载状态-

仅在存在或不存在 常量和/或volatile是等效的。也就是说,常量和volatile 忽略每个参数类型的类型说明符[…]

仅位于最外层的const和volatile类型说明符 以这种方式忽略参数类型规范;常数 和隐藏在参数类型中的易失性类型说明符 规范是重要的,可用于区分 重载函数声明。[……]

确定要声明、定义或调用哪个函数时。 特别是,对于任何类型的T,“指向T的指针”,“指向常量T的指针,” 和“指向volatile T的指针”被视为不同的参数类型, “引用T”、“引用常数T”和“引用 挥发性T.“

所以,

void validateAttribute(Model &model, std::string &attribute) override;
不一样

void validateAttribute(Model &model, const std::string &attribute);
其次,如果您使用C++11或更高版本,并在函数声明中使用override关键字,则可以避免遇到此类错误,如下所示。 使用override关键字,除非派生类中的函数签名与基类中的函数签名匹配,否则此代码将不允许编译

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

    void validateAttribute(Model &model, std::string &attribute) override;
    ~RequiredValidator();
    std::string name() const;
};
编辑:p.s.覆盖需要虚拟关键字。因此,

virtual void validateAttribute(Model &model, std::string &attribute) override;

删除所有不相关的代码让我们看看基类和继承类的签名:

class Validator {
public:
    virtual void validateAttribute(Model &model, const std::string &attribute);
};

class RequiredValidator : public Validator {
public:
    void validateAttribute(Model &model, std::string &attribute);
};
在基类的::validateAttribute中,您为其参数Model&Model和const std::string&attribute提供了属性,在派生类的::validateAttribute中,您为其参数Model&Model和std::string&attribute提供了属性

这里的冲突是const std::string&和std::string&。请事先使这两个函数完全匹配,或者在您的情况下,由于您试图使用多态性,您可以在派生类中通过执行以下操作来解决此问题:

/*virtual*/ void validateAttribute( Model& model, std::string& string ) override;

这里的override关键字将生成一个编译器错误,用于解释问题所在。如果您计划从这个派生类继承,请不要忘记添加virtual。是否需要重新定义virtual关键字?因为错误:标记为“override”的非虚拟成员函数隐藏虚拟成员函数validateAttribute签名在基和派生类中必须相同只有一件事:对“Validator::name[abi:cxx11]const”的未定义引用。如何修复?@exru:表示缺少虚拟std::string name const;的实现;。谢谢兄弟,我自己修好的。它说的是:1.听编译器说。教英语3。阅读docas e.t.c.所有用我糟糕的英语拍摄的麻烦事。但我正在努力,我花了很多时间在PHP上。我在C++上写了2个月的感谢。@ EXRU,实际上,如果有一个const但不是一个引用,那么它就可以超载了,即ValueRealEntAdvestODel&模型,STD::String属性和ValueValueAtestMeToDel&模型,const STD::String and Atple不会有这个问题。当然,这不是我们想要做的。。我只是想详细说明一点。区别在于引用和指针!对他们来说,康斯特起了作用。谢谢兄弟。我修好了@Joey Mallone您是指评论第二个签名中的const std::string属性吗?因为T和const T在签名中是相同的,但是T和const T&肯定不是…@MaxLanghof,是的。但我现在无法编辑评论:我的意思是,void validateAttributeModel&model、std::string属性和void validateAttributeModel&model、const std::string属性可以重载。在两个声明中都没有(&N)。