Реализация чистой виртуальной функции C++ и заголовочные файлы

У меня возникли проблемы с реализацией чисто виртуальных функций, унаследованных от какого-то абстрактного класса, когда рассматриваемые классы разделены на файлы *.h и *.cpp. Компилятор (g++) сообщает мне, что производный класс не может быть создан из-за существования чистых функций.

/** interface.h**/
namespace ns
{
    class Interface {
        public:
            virtual void method()=0;
    }
}

/** interface.cpp**/
namespace ns
{
    //Interface::method()() //not implemented here
}

/** derived.h **/
namespace ns
{
    class Derived : public Interface {
        //note - see below
    }
}

/** derived.cpp **/
namespace ns
{
    void Derived::Interface::method() { /*doSomething*/ }
}

/** main.cpp **/
using namespace ns;
int main()
{
    Interface* instance = new Derived; //compiler error
}

Означает ли это, что мне нужно объявить метод() дважды — в интерфейсе *.h и в derived.h тоже? Неужели нет другого выхода?


person Neo    schedule 13.01.2011    source источник
comment
Во-первых, нет причин иметь файл .cpp, в котором единственное — это пустое пространство имен. Вам не нужен файл реализации для заголовка, объединяющего абстрактный класс.   -  person Falmarri    schedule 13.01.2011


Ответы (2)


Вы забыли объявить Derived::method().

Вы хотя бы пытались его определить, но написали Derived::Interface::method(), а не Derived::method(), но даже не пытались его объявить. Поэтому его не существует.

Следовательно, Derived не имеет method(), поэтому чисто виртуальная функция method() из Interface не была переопределена... и, следовательно, Derived также является чисто виртуальной и не может быть реализована.

Кроме того, public void method()=0; не является допустимым C++; это больше похоже на Java. Чисто виртуальные функции-члены на самом деле должны быть виртуальными, но вы не написали virtual. За спецификаторами доступа следует двоеточие:

public:
    virtual void method() = 0;
person Lightness Races in Orbit    schedule 13.01.2011
comment
Бит void, вероятно, опечатка, это тоже не java. - person time4tea; 13.01.2011
comment
@time4tea: Действительно, это тоже недействительная Java, но с отсутствующим двоеточием и намеком на то, что спецификатор доступа рассматривается как нечто, присоединенное к объявлению, это чертовски ближе, чем к C++! - person Lightness Races in Orbit; 13.01.2011
comment
Синтаксис был моей опечаткой, см. мой комментарий к первому сообщению :) извините за это. Кроме того, Derived::Interface::method() — это моя попытка определить функцию, которая должна быть унаследована от интерфейса. Мой первоначальный вопрос был примерно таким: могу ли я реализовать (определить) унаследованную чистую виртуальную функцию без явного объявления ее в файле .h производного класса? Причина, по которой я хотел бы сделать это, состоит в том, чтобы не загромождать мой заголовочный файл, когда класс наследует несколько интерфейсов, каждый из которых содержит несколько чистых виртуальных... - person Neo; 13.01.2011
comment
@Neo: И ответ - нет. :) - person Lightness Races in Orbit; 13.01.2011
comment
@Thomalak Geret'kal: Ах. Жалость. :( Спасибо большое за вашу помощь :) - person Neo; 13.01.2011

Вы должны объявить свой метод в подклассе.

// interface.hpp
class Interface {
public:
    virtual void method()=0;
}

// derived.hpp
class Derived : public Interface {
public:
    void method();
}

// derived.cpp
void
Derived::method()
{
    // do something
}
person robert    schedule 13.01.2011
comment
Я думаю, вы имеете в виду объявлять (не определять). - person Mike S; 10.09.2015
comment
@MikeSlutsky да, я сделал. - person robert; 10.09.2015
comment
@ Роберт Спасибо за ответ. Можно поподробнее о причинах этого? Исходя из Java, это кажется очень грязным. Когда у нас есть много производных разных классов и много методов в базовом интерфейсе, нам нужно изменить много файлов в случае изменения базового интерфейса. - person Manuel Selva; 30.09.2015
comment
@ManuelSelva вы не можете определить метод в классе, если он не объявлен в этом классе. Это не зависит от того, происходит ли этот класс от чего-либо. - person robert; 30.09.2015