Обновить
Фактический контекст заключается в том, что мне нужно создать пакет для отправки в NIST, пытаясь протестировать алгоритм распознавания лиц, над которым я работаю. API для использования можно найти на NIST API и проект для мерзости в мерзавец проект
Некоторый код для составления резюме сценария:
хиджры — интерфейс A, составленный из чисто виртуальных методов и одного статического метода (frvt11.h в проекте NIST)
class A {
public:
virtual ~A() {}
virtual void pure_virtual_method_a() = 0;
virtual void pure_virtual_method_b() = 0;
static int static_method();
}
b.h — заголовочный файл для b.cpp, где реализованы методы интерфейса A
#include "a.h"
class B : A {
public:
void pure_virtual_method_a();
void pure_virtual_method_b();
static int static_method();
}
b.cpp — Реализация методов интерфейса.
#include "b.h"
void pure_virtual_method_a() {/*implementation*/};
void pure_virtual_method_b() {/*implementation*/};
int static_method() {/*implementation*/};
c.cpp — Файл только с основным методом, и я хочу создать экземпляр объекта B для использования его методов.
#include "b.h"
int main(){
B obj;
obj.pure_virtual_method_a();
return 0;
}
Вопрос 1: Чтобы создать экземпляр объекта B в c.cpp, нужно ли мне создавать заголовочный файл b.h, как описано выше? Это кажется излишним! Похоже, интерфейс A так ненужен 🙁
Вопрос 2: Представленный код является правильным способом реализации интерфейса A и использования объекта B?
Вопрос 3: мне нужно объявить конструктор B в b.h и реализовать его в b.cpp?
Вопрос 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.
Вопрос 1.
Вы можете использовать Factory Pattern, тогда вы можете добавить b.h только в файлах Factoru? и вернуть указатели или умный указатель на класс А. Например, это может быть заводская функция:
std::unique_ptr<A> getObject(/*params*/)
{
return std::make_unique<B>(/*params*/)
}
А затем в файле c.cpp:
auto obj = getObject(/*params*/);
obj->pure_virtual_method_a();
Затем вы можете создать еще одну реализацию A
интерфейс и вернуть их с завода.
Вопрос 2.
должно быть class B : public A
а также
void B::pure_virtual_method_a() {/*implementation*/};
void B::pure_virtual_method_b() {/*implementation*/};
int B::static_method() {/*implementation*/};
Вопрос 3
Если вам нужен конструктор в class A
или конструктор именно для class B
, вам нужно определить и реализовать конструктор класса B.