Реализация интерфейса C ++ и встраивание в подклассы объектов - PullRequest
0 голосов
/ 03 июля 2018

Обновление Фактический контекст заключается в том, что мне нужно создать пакет для отправки в NIST, пытаясь протестировать алгоритм распознавания лиц, над которым я работаю. API для использования можно найти в NIST API , а проект для git - в git project

Некоторый код для составления резюме сценария:

a.h - интерфейс 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 - Реализация методов интерфейса A.

#include "b.h"

void pure_virtual_method_a() {/*implementation*/};
void pure_virtual_method_b() {/*implementation*/};
int static_method() {/*implementation*/};

c.cpp - Файл, содержащий только метод main и в котором я хочу создать экземпляр объекта 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?

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Вопрос 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 .

0 голосов
/ 03 июля 2018

Вопрос 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.

...