шаблоны — почему это «виртуальность»? методов неявно распространяются в C ++?

В чем причина устранения возможности прекращения распространения методов виртуальности?

Позвольте мне быть более ясным: в C ++, независимо от того, пишете ли вы «virtual void foo ()» или «void foo ()» в производном классе, он будет виртуальным до тех пор, пока в базовом классе foo объявлен виртуальным.

Это означает, что вызов foo () через производный указатель * приведет к поиску в виртуальной таблице (в случае, если функция производная 2 переопределяет foo), даже если это поведение не требуется программисту.

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

template <class T>
class Iterator // Here is an iterator interface useful for defining iterators
{              // when implementation details need to be hidden
public:
virtual T& next() { ... }
...
};

template <class T>
class Vector
{
public:
class VectIterator : public Iterator<T>
{
public:
T& next() { ... }
...
};
...
};

В приведенном выше примере базовый класс Iterator может использоваться для достижения формы «стирания типа» гораздо более понятным и объектно-ориентированным способом. (Увидеть http://www.artima.com/cppsource/type_erasure.html для примера стирания типа.)

Но, тем не менее, в моем примере можно использовать объект Vector :: VectIterator напрямую (что будет сделано в большинстве случаев) для доступа к реальному объекту без использования интерфейса.

Если бы виртуальность не распространялась, вызовы Vector :: VectIterator :: next () даже из указателя или ссылки не были бы виртуальными и могли бы быть встроенными и работать эффективно, как если бы интерфейс Iterator не существовал.

12

Решение

C ++ 11 добавил контекстное ключевое слово final для этого.

class VectIterator : public Iterator<T>
{
public:
T& next() final { ... }
...
};

struct Nope : VecIterator {
T& next() { ... } // ill-formed
};
9

Другие решения

Простой ответ: не смешивайте конкретные и абстрактные интерфейсы! Очевидным подходом в вашем примере будет использование неvirtual функция next() который делегирует virtual функция, например, do_next(), Производный класс переопределит do_next() возможно делегирование неvirtual функция next(), Так как next() функции скорее всего inline Там нет никаких затрат, связанных с делегированием.

4

На мой взгляд, одной из причин такого распространения является virtual деструкторов. В C ++, когда у вас есть базовый класс с некоторыми virtual Методы, которые вы должны определить деструктор virtual, Это связано с тем, что некоторый код может иметь указатель базового класса, который фактически указывает на производный класс, а затем пытается удалить этот указатель (см. Это вопрос для более подробной информации).
Определив деструктор в базовом классе как vritual Вы можете убедиться, что все указатели базового класса, указывающие на производный класс (на любом уровне наследования), будут удалены должным образом.

0

Я думаю, причина в том, что было бы очень сложно удалить виртуальность частично через структуру наследования (у меня есть пример сложности ниже).

Однако, если вас беспокоит микрооптимизация удаления нескольких виртуальных вызовов, я бы не стал беспокоиться. Пока вы встраиваете код виртуального дочернего метода И ваш итератор передается по значению, а не по ссылке, хороший оптимизирующий компилятор будет уже быть в состоянии увидеть динамический тип во время компиляции и встроить все это для вас, несмотря на то, что это виртуальный метод!

Но для полноты рассмотрим следующее на языке, который можно де-виртуализировать:

class A
{
public:
virtual void Foo() { }
};

class B : public A
{
public:
void Foo() { } // De-virtualize
};

class C: public B
{
public:
void Foo() { } // not virtual
};

void F1(B* obj)
{
obj->Foo();
static_cast<A*>(obj)->Foo();
}

C test_obj;
F1(test_obj);   // Which two methods are called here?

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

0
По вопросам рекламы [email protected]