2017-02-04 13 views
3

Это моя ситуация:Ошибка при переопределении C++ виртуальная функция

class Filter3by3 { 
public: 
    virtual inline Mat convolution((Mat & mat, int i, int j, int rows, int cols) { 
code 

    } 
}; 

class MySobel: public Filter3by3 { 
public: 
    inline Vec3b convolution(Mat & mat, int i, int j, int rows, int cols) { 
    code 
    } 
}; 

Теперь, когда я звоню: метод

Filter3by3 f = choose_filter(filtername); // Returns a Sobel filter 
Mat mat; 
s.convolution(args); 

Базовый класс называется. Я довольно новичок в правилах привязки методов C++, так что вы можете сказать мне, где я ошибаюсь? Я ценю вашу помощь.

UPDATE Оказывается, что даже с виртуальной рядный Mat свертка ((Mat & мат, Int я, Int J, внутр строки, внутр смещ_по_столбцам) Это не работает.

Это работает программа, составленная с г ++ -std = C++ 11

#include <iostream> 

using namespace std; 

class Filter { 
public: 
    Filter() { } 
    virtual int ehi() { 
    cout << "1" << endl; 
    return 1; 
    } 

}; 

class SubFilter : public Filter { 
public: 
    SubFilter() : Filter() { } 

    int ehi() { 
    cout << "2" << endl; 
    return 2; 
    } 

}; 

    Filter choose_filter(){ 
    SubFilter f; 
    return f; 
    } 

    int main(int argc, char* argv[]) { 

    Filter f = choose_filter(); 
    f.ehi(); 
    return 0; 
    } 

он печатает 1 вместо 2. Я использовал виртуальный для обеспечения динамического связывания, но это, кажется, не достаточно, а также с «переопределить» ключевое слово.

+2

Чтобы переопределить функцию, она должна иметь точную подпись базового класса. Поскольку вы изменяете тип возвращаемого значения, вы не переопределяете функцию базового класса. Однако с кодом, который вы показываете, должна быть вызвана правильная функция. Это копия-вставка из вашего * фактического * кода? Не могли бы вы попытаться создать [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и показать нам. –

+1

Что касается вашего редактирования, вы вызываете виртуальную функцию на 'f' или' s'? Что такое '' '? И если это действительно 'f', то вы, вероятно, должны читать о [* обрезке объектов *] (http://stackoverflow.com/questions/274626/what-is-object-slicing). –

+0

Полиморфизм работает только с помощью указателей или ссылок на базовый класс. У вас есть нарезка объектов. –

ответ

1

При назначении объекта производного класса к объекту базового класса, как это, вы не достижения динамической диспетчеризации, можно достичь slicing (все дополнительные элементы данных SubFilter теряются)

Filter choose_filter(){ 
    SubFilter f; 
    return f; 
    } 

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

std::shared_ptr<Filter> choose_filter(){ 
    return std::make_shared<SubFilter>(); 
    } 

    int main(int argc, char* argv[]) { 

    auto f = choose_filter(); 
    f->ehi(); 
    return 0; 
    } 
+0

Пробовал, но не компилирует – diningphil

+0

'shared_ptr' и' auto' были введены в C++ 11 , также '#include ' для 'shared_ptr'. Обычные указатели или ссылки будут работать одинаково, минус потенциал утечки памяти. [Проверьте это] (http://en.cppreference.com/w/cpp/language/virtual). – w1ck3dg0ph3r

6

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

+0

Спасибо, это была действительно глупая ошибка :) – diningphil

+1

Только одна незначительная коррекция: ковариантные типы возврата в порядке, хотя и редки.То есть допускаются разные типы возвращаемых значений, если функция в базовом классе и функция в производном классе как указатели возврата, так и возвращаемые ссылки и возвращаемый тип функции в производном классе являются указателями или ссылками на тип, который является полученный от типа, указателя или ссылки, возвращаемого функцией в базовом классе. (Phew, это было изнурительно!), Например, 'производная * D :: f()' переопределяет "виртуальную базу * B :: f()', когда 'D' выведена из' B', а 'производный' получен из' base'. –

+0

спасибо, я забыл об этом. –

1

В C++ есть ключевое слово с именем override. Это точно решить эту проблему вы упомянули:

struct MySobe l: Filter3by3 { 
    inline Vec3b convolution(Mat & mat, int i, int j, int rows, int cols) override { code } 
}; 

Присутствие override гарантировать, что метод действительно переопределяет метод базового класса.

В вашем коде это приведет к ошибке компиляции, потому что производный класс не переопределяет, так как подпись отличается.

+1

Нет, это не решит проблему, так как подписи обоих методов не совпадают. – Soeren

+0

@Soeren Я уточнил ответ. –

+0

«он сделает компиляцию» - я считаю, что вы хотите, чтобы это было «Это вызовет ошибку компиляции». –