2016-07-28 4 views
-1

Я понимаю, почему вы не можете просто нарисовать указатель функции элемента производного класса на указатель функции элемента базового класса, как описано here.Листинг виртуального переопределения на базовый чистый виртуальный член

Но, учитывая этот фрагмент:

struct base 
{ 
    virtual void foo() = 0; 
}; 

struct derived : base 
{ 
    void foo() override {}; 
}; 

struct invoker 
{ 
    typedef void(base::*target)(); 

    invoker(base* b, target t) 
    { 
     (b->*t)(); 
    } 
}; 

template<typename B, typename D> 
void (B::*cast(void (D::*method)()))() 
{ 
    return static_cast<void(B::*)()>(method); 
} 

derived d; 
invoker bad(&d, &derived::foo); //C2664 
invoker good(&d, cast<base>(&derived::foo)); 

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

+1

Непонятно, какое оформление вы просите. Если бы вы были высшим руководителем проектного комитета C++, что бы вы сделали? Не беспокойтесь о последовательности или правильности, просто покажите, что вы хотите добавить в C++. Если вы просто хотите сообщить компилятору, что 'base :: foo' существует в' base', вы можете просто написать '& base :: foo'. –

+0

@ н.м. Я хочу избежать явного приведения в действие: D Но это был скорее вопрос «есть ли способ, которым я не знаю» типа вопроса. –

+1

Нет, не делайте бросок. Просто начните с '& base :: foo'. Что делает '& производное :: foo' делать то, что' & base :: foo' не может? –

ответ

2

Нет необходимости манипулировать типом &derived::foo. Вместо этого можно использовать только &base::foo.

Указатели на функции-члены уважают виртуальность. Этот вызов

base* pBase = new derived; 
auto pFoo = &base::foo; 
(pBase->*pFoo)(); 

будет на самом деле назвать derived::foo, так же, как простой вызов pBase->foo() бы.

0

Даже если есть гарантия, что он реализован, он может использовать дополнительные данные, объявленные только в derived. Возможное решение - использовать указатели на функции и передать this в качестве первого параметра (это также показывает, почему вы не можете сделать это через virtual).

+0

Поскольку я передаю 'base *', я вернусь к правильному переопределению из-за полиморфизма времени выполнения, поэтому я не могу получить доступ к чему-либо, что там не существует. Или я неправильно понял вас? –

+0

Добавьте 'int i;' к производному и do 'i = 0xDEADBEEF;' к 'производному :: foo()', чтобы понять, что я имею в виду. Он работает наоборот: вы можете передать указатель функции «Base», где ожидается «производный». Обратите внимание, что * вы знаете, что вы передаете 'производный *', но компилятор C++, возможно, не знает этого. – lorro

+0

Нет, я не могу, поскольку я не могу построить экземпляр 'Base', поскольку он имеет чистый виртуальный член , Я не говорю об общем случае, а о том, где цель актера - чистый виртуальный член «Базы». –

0

Рассмотрим следующую иерархию алмазную:

struct base { 
virtual void foo() = 0; 
}; 

struct D1 : public virtual base { 
virtual void foo() override; 
}; 

struct D2 : public virtual base { 
virtual void foo() override; 
}; 

struct Derived : public virtual D1, D2 { 
virtual void foo() final; 
}; 

Теперь рассмотрим ситуацию, когда вентиляционный разрешено из Derived :: * базировать :: *. Какую функцию следует вызывать? Компилятор теряет информацию о том, какой из D1 :: foo, D2 :: foo или Derived :: foo вы хотите вызвать, поскольку эта информация была отброшена. Чтобы избежать такого рода двусмысленности, такой взлет не разрешен.

+0

Я предполагаю, что моя точка отказа заключалась в том, что поиск в vtable происходит и с указателями на функции (и в этом случае правильный метод будет фактически вызван), но я предполагаю, что этого не происходит. –

+0

"_Какую функцию нужно вызывать? _" 'Foo()', я думаю – curiousguy

 Смежные вопросы

  • Нет связанных вопросов^_^