Указатель функции базового класса указывает на функцию-член дочернего класса?

Я знаю, что это звучит ужасно запутанно, у меня есть базовый шаблонный класс, который имеет указатель на функцию, дочерний класс (который больше не является классом шаблона) должен использовать этот указатель функции, чтобы указать на функцию-член дочернего класса, и я получаю все виды ошибок .. Я нарушил какой-то универсальный закон C ++? вот псевдокод:

template <class T>
class Base{
    public:
       typedef void (Base<T>::*fptr) (char in);
       void funcA(fptr FuncToCall){
                 FuncToCall('a');
       }
       ...
    };

class Child:public Base<char>{
   public: 
       void funcToCall(){...}
       void funcB(){
          funcA(funcToCall);
       }
}

Вот сообщение об ошибке, которое я получил:

ошибка C2664: 'Base ‹T> :: funcA': невозможно преобразовать параметр 1 из 'void (__thiscall Child :: *) (char)' в 'void (__thiscall Base‹ T> :: *) (char)'


person Yonk    schedule 13.10.2010    source источник


Ответы (1)


Ваш код недействителен.

Во-первых, в C ++ для создания указателя на функцию-член вы всегда должны использовать оператор & и полное имя члена, что означает, что ваш вызов funcA должен выглядеть следующим образом

funcA(&Child::funcToCall); // close, but not yet, see "secondly" 

Во-вторых, указатели на элементы контравариантны. Если вы хотите инициализировать объект указателя базового члена значением указателя производного члена, вы должны использовать явное static_cast

funcA(static_cast<fptr>(&Child::funcToCall));

Обратите внимание, что это допустимое, но потенциально опасное преобразование, поскольку теперь вы несете ответственность за то, чтобы фактический объект, используемый в левой части вызова (см. «В-третьих»), имел этот член.

В-третьих, чтобы вызвать функцию с помощью такого указателя, вы должны указать конкретный объект с левой стороны, поэтому вызов в funcA должен выглядеть следующим образом (я предполагаю, что вы хотите вызвать его для объекта *this)

(this->*FuncToCall)('a');

В-четвертых, ваш funcToCall должен иметь параметр. Где это находится?

person AnT    schedule 13.10.2010
comment
Спасибо, я попробовал, я получаю эту ошибку: (аналогично первой) ошибка C2664: 'Base ‹T› :: funcA': не удается преобразовать параметр 1 из 'void (__thiscall Child :: fptr) (char)' в 'void (__thiscall Base ‹T› :: *) (char)' - person Yonk; 13.10.2010
comment
@Yonk: Пожалуйста, обратите внимание. Либо вы забыли добавить static_cast, как показано в моей второй части, либо вы компилируете другой код. - person AnT; 13.10.2010
comment
Да, я добавил это, по-прежнему получаю аналогичную ошибку. единственная разница в том, что Child :: * стал Child :: fptr - person Yonk; 13.10.2010
comment
@Yonk: Это означает, что вы изменили код из исходной версии. Я не телепат, я не знаю, что еще вы с ним сделали. Ваш исходный код с моими модификациями компилируется и отлично работает. - person AnT; 13.10.2010