Как вызвать точный метод производного класса?

В продолжение моего предыдущего вопроса: Как вернуть производный тип?

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();

    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???

The same virtual method name() working as i want, but validateAttribute() called from base class only.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
74
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Посмотрите внимательно, как вы определили void RequiredValidator::validateAttribute()

Вы можете заметить, что подпись немного отличается от базовой (std::string &attribute не const)

есть ключевое слово override, которое поможет компилятору улавливать такие типы опечаток.

Нужно ли мне переопределить тогда "виртуальное" ключевое слово? Потому что «ошибка: невиртуальная функция-член, помеченная как« переопределить », скрывает виртуальную функцию-член»

user7997307 15.01.2019 11:20

подпись validateAttribute должна быть идентична в базе и в производном классе

Eyal Cinamon 15.01.2019 11:31

Только одно: неопределенная ссылка на `Validator :: name [abi: cxx11] () const '. Как это исправить?

user7997307 15.01.2019 11:36

@exru: там написано, что не хватает реализации virtual std::string name() const;.

Matthieu Brucher 15.01.2019 11:49

Спасибо, братан, я исправил сам. Там написано, что: 1. слушать компилятор 2. учить английский 3. читать документы и т. д. Все проблемы на моем плохом английском. Но я стараюсь)) И я много времени проводил с PHP. Пишу на C++ всего 2 месяца))) Спасибо за помощь.

user7997307 15.01.2019 11:57
  • Во-первых, как указывали другие,

§13.1 where the Standard discusses about declarations that cannot be overloaded states -

Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored [...]

Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations. [...]

when determining which function is being declared, defined, or called. "In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.”

Следовательно,

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

это не то же самое, что

void validateAttribute(Model &model, const std::string &attribute);
  • Во-вторых, вы можете избежать столкновения с такими ошибками, если у вас C++11 или новее с использованием ключевого слова 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. override требует ключевого слова virtual. Следовательно,

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

@exru, на самом деле, если бы была константа, но не ссылка, тогда было бы нормально перегрузить, т.е. void validateAttribute(Model &model, std::string attribute) и void validateAttribute(Model &model, const std::string &attribute) не имели бы этой проблемы. (НО, конечно, это не то, что мы хотим делать ...) Я просто хотел уточнить точку. Разница только для использованная литература и указатели! Для них const имеет значение.

Duck Dodgers 15.01.2019 11:39

Спасибо, бро. Я исправил!

user7997307 15.01.2019 11:42

@JoeyMallone Вы имели в виду const std::string attribute во второй подписи вашего комментария? Потому что T и const T имеют одинаковые искажения в подписях, но T и const T& определенно не ...

Max Langhof 15.01.2019 11:57

@MaxLanghof, да. Но сейчас я не могу редактировать комментарий. :( Я имею в виду, нет, void validateAttribute(Model &model, std::string attribute) и void validateAttribute(Model &model, const std::string attribute) можно было бы перегрузить. В обоих объявлениях нет &.

Duck Dodgers 15.01.2019 11:57

Удалив весь ненужный код, давайте посмотрим на сигнатуры базового и унаследованного классов:

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, если вы планируете наследовать от этого производного класса.

Другие вопросы по теме