Связывание не выполняется, если отсутствует реализация неиспользуемого чисто виртуального метода - PullRequest
1 голос
/ 18 марта 2011

У меня есть класс, который наследуется от класса с чисто виртуальными функциями.

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

#include <iostream>

class ibase {
    public:
        virtual void foo() = 0;
        virtual void boo() = 0;
};

class base1 : public ibase {
    public:
        virtual void foo(){ std::cout<<"base1::foo"<<std::endl; }
        virtual void boo(){ std::cout<<"base1::boo"<<std::endl; }
};

class base2 : public ibase {
    public:
        virtual void foo() { std::cout<<"base2::foo"<<std::endl; }
        virtual void boo();
};

int main()
{
    ibase *inst1 = new base1;
    ibase *inst2 = new base2;

    inst1->foo();
    inst1->boo();
    inst2->foo();
}

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

g++ dfg.cpp  -ansi -pedantic -Wall

в этом примере был получен следующий вывод (с использованием g ++ 4.3.0):

/tmp/ccv6VUzm.o: In function `base2::base2()':
dfg.cpp:(.text._ZN5base2C1Ev[base2::base2()]+0x16): undefined reference to `vtable for base2'
collect2: ld returned 1 exit status

Может кто-нибудь объяснить, почему не удается установить связь?Метод boo () не вызывается.

Ответы [ 6 ]

4 голосов
/ 18 марта 2011

Создан vtable для base2 - вы используете base2. Vtable ссылается boo() - так что вам нужно определить его.

10,3 / 8

Виртуальная функция, объявленная в классе должны быть определены или объявлены чистыми (10.4) в этом классе или оба; но нет требуется диагностика (3.2).

3 голосов
/ 18 марта 2011

Правило единого определения гласит, что каждая функция used должна быть определена ровно один раз. Определение термина used включает следующую строку:

Виртуальная функция используется, если она не чистый

Это означает, что все не чистые виртуальные функции должны быть определены, даже если они не вызваны

1 голос
/ 18 марта 2011

boo не может быть вызван в реальности, но он используется для построения v-таблицы для base2.

Вы должны определить, какое поведение произойдет, если у кого-то есть base2 и он вызывает boo () (через указатель базового класса), даже если в коде нет точки, где это фактически вызывается. Это часть контракта по внедрению ibase.

Дизайн, конечно, несовершенен, и если вам нужен класс, который допускает только foo, то для этого должен быть интерфейс.

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

1 голос
/ 18 марта 2011

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

1 голос
/ 18 марта 2011

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

Создайте пустое тело для метода, и вы должны быть готовы.

0 голосов
/ 18 марта 2011

Вы просто забыли реализовать virtual void base2::boo (). Вы должны реализовать это, чтобы создать экземпляр класса base2. В противном случае вы можете оставить его чисто виртуальным, не объявив его в base2 классе.

...