C ++ проблема виртуального метода - PullRequest
0 голосов
/ 10 мая 2011

У меня есть две структуры, в которых я пытаюсь переписать метод в базовой структуре.

Базовая структура определяется как:

 template <class T>
 struct compareFunction : public std::binary_function<T,T,bool> {
    virtual bool operator() (const T & first, const  T & second) {
        //This function is always called
        return first < second;
    }
 };

Структура, которую япопытка создать подкласс с определяется как:

template <class Key, class T>
struct valuecomparer : public compareFunction<std::pair<Key,T> > {
    std::binary_function<Key, Key,bool> comparer;

    bool operator() (const std::pair<Key, T>& x, const std::pair<Key, T> & y) {
            //This function is never called
            Key tx = x.first;
            Key ty = y.first;
            if(tx < ty) {
               return true;
            } else {
               return false;
            }
    }
};

Я не вижу, что я делаю здесь неправильно, любая помощь будет принята с благодарностью.В идеале, метод в valuecomparer должен вызываться вместо метода в compareFunction.

Он вызывается в основном так (необязательно допустимый синтаксис, но пытается понять идею):

typedef compareFunction<T> cmpType; //Inside a class definition, T is std::pair<int,double>
valuecomparer<int,double> compareVar;
compareVar.comparer = std:less<int>();
cmpType x = compareVar;
x.compare(std::pair<int,double>(8,20.0),std::pair<int,double>(8,25.0));

Очевидно, что после переключения хранилища с чистой структуры на указатель структуры в классе, который использует базовую структуру (и, следовательно, производную структуру), все работает.Спасибо за помощь:)

Ответы [ 3 ]

2 голосов
/ 10 мая 2011

Согласно опубликованному вами коду, для вызова функции переопределенного производного класса, вы ДОЛЖНЫ вызываете ее из указателя или ссылки на тип базового класса, а не объектачей тип относится к самому базовому классу.Поэтому, когда вы создаете код, подобный этому:

cmpType x = compareVar;
x(std::pair<int,double>(8,20.0),std::pair<int,double>(8,25.0));

, он всегда будет вызывать определение функции в базовом классе, поскольку нет функции, которую можно было бы использовать для вызова полиморфной производной функции.Конструктор копирования копирует только записи v-таблицы и связанные члены из базового класса.Поэтому, когда вы вызываете метод для объекта типа базового класса, даже если вы создали этот объект из копии производного класса, вы все равно в конечном итоге вызовите метод базового класса.Вам нужно будет сделать что-то вроде этого:

cmpType& x = compareVar;
x(std::pair<int,double>(8,20.0),std::pair<int,double>(8,25.0));

Теперь, когда метод operator() вызывается на x, используется правильная запись v-таблицы, то есть переопределенная версия operator() внутри valuecomparer.

1 голос
/ 10 мая 2011

Проблема в том, что из вашего псевдо-кода вы нарезаете свой компаратор:

typedef compareFunction<T> cmpType; //Inside a class definition, T is std::pair<int,double>
valuecomparer<int,double> compareVar;
compareVar.comparer = std:less<int>();
cmpType x = compareVar;                     // *** SLICED HERE ****
x.compare(std::pair<int,double>(8,20.0),std::pair<int,double>(8,25.0));

Самым простым решением, учитывая контекст, было бы изменение объявления x нассылка на cmpType, вместо полноценного экземпляра.

Редактировать: Если присмотреться, вышеприведенное не будет работать вообще (вы сказали, что это был псевдо), но с учетомнамерение, похоже, что вы имели в виду:

valuecomparer<int,double> compareVar;
compareVar.comparer = std:less<int>();
compareFunction<pair<int, double> > x = compareVar;                     // *** SLICED HERE ****
x.compare(std::pair<int,double>(8,20.0),std::pair<int,double>(8,25.0));
0 голосов
/ 10 мая 2011

Если вы используете valuecomparer для std::map, то вам не хватает того факта, что элемент на карте определяется как std::pair<const Key, Val>. Видите часть const? :) Добавьте это к своим std::pair<> с. Если это не проблема, сообщите, где и как вы на самом деле используете эти функторы.

...