Вопрос 1
Вы пропускаете точку с запятой после закрывающей фигурной скобки, и лучше указать, что чистые виртуальные методы, которые вы реализуете в B
, помечены как override
. Это позволяет компилятору выдавать предупреждения в случае, если вы забудете изменить любое из переопределенных объявлений методов, как только изменится соответствующий чистый виртуальный метод в A
. Таким образом, вы получите:
#include "a.h"
struct B : public A {
void pure_virtual_method_a() override;
void pure_virtual_method_b() override;
static int static_method();
};
Из этого также ясно, что для того, чтобы компилятор мог объявить B
как тип, A
также должен быть объявлен. Например, как компилятор может проверить ключевое слово override
, если оно еще не имеет объявления A
. В случае, если у вас не было бы никаких переопределенных виртуальных методов, A
все еще должен быть известен, так как компилятор должен иметь возможность определять размер B
.
Кроме того, как упоминалось в комментариях, объявление B
как struct
позволяет вам отбрасывать ключевое слово public
, поскольку видимость по умолчанию для struct
общедоступна в отличие от видимости по умолчанию для private
для класс. Это единственная разница между классами и структурами в C ++. Таким образом, для интерфейсов использование структур более естественно.
Вопрос 2
Не полностью. b.cpp должен выглядеть примерно так:
#include "b.h"
void B::pure_virtual_method_a() {/*implementation*/};
void B::pure_virtual_method_b() {/*implementation*/};
int B::static_method() {/*implementation*/};
В противном случае вы объявляете и определяете три метода в глобальном пространстве имен, и компоновщик будет жаловаться на неопределенные ссылки на три метода B
, объявленных в b.h .
Кроме того, B
нужно знать, как получить из A
, публично, защищенно или приватно.
Кроме того, было бы неплохо добавить в заголовочные файлы элементы защиты включения, чтобы компилятор не видел дважды одно и то же объявление типа при компиляции объектного файла, например a.o
или b.o
:
#ifndef B_H
#define B_H
#include "a.h"
struct B : public A {
...
};
#endif
Наконец, static_method()
также нужна реализация для A
, статические методы не могут быть виртуальными.
Вопрос 3
Вам необязательно реализовывать конструктор для B
. Если вы не определите его, компилятор сгенерирует конструктор по умолчанию для B
. Однако, если вы определяете конструктор не по умолчанию для A
, вам нужно будет определить его для B
на тот случай, если вы хотите создать экземпляры типа B
. Конструктор может быть встроен в заголовочный файл или может быть определен в b.cpp .