C++ 接口实现和子类对象实例化

C++ Interface Implementation and Subclassed Object Instatiation

更新 实际情况是我需要创建一个包以提交给 NIST,以尝试测试我正在研究的面部识别算法。要使用的 API 可以在 NIST API and the project to git is at 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 - 一个只有主要方法的文件,我想在其中实例化 B 的对象以使用其方法。

#include "b.h"

int main(){
    B obj;
    obj.pure_virtual_method_a();
    return 0;
}

问题一:c.cpp中实例化一个B的对象,是否需要像上面那样写头文件b.h ?这似乎是多余的!看起来接口 A 是不必要的:-(

问题 2:提供的代码是否以正确的方式实现接口 A,并使用类型 B 的对象?

问题3:是否需要在b.h中为B声明构造函数并在b.cpp中实现?

问题一

你可以使用工厂模式,那么你只能在 Factoru 文件中添加 b.h 吗?和 return 指向 A class 的指针或智能指针。例如,它可以是像这样的工厂函数:

std::unique_ptr<A> getObject(/*params*/)
{
    return std::make_unique<B>(/*params*/)
}

然后在 c.cpp 文件中:

auto obj = getObject(/*params*/);
obj->pure_virtual_method_a();

然后你可以创建另一个 A 接口的实现,并且 return 它们来自工厂。

问题二

应该是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 class 构造函数。

问题一

你在右花括号后少了一个分号,最好指定你在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。例如,如果编译器还没有 A 的声明,它将如何检查 override 关键字。如果您没有任何重写的虚方法,A 仍然需要知道,因为编译器需要能够推断出 B.

的大小

此外,如评论中所述,将 B 声明为 struct 允许您删除 public 关键字,因为 struct 的默认可见性是public 对比 private 默认可见性 class。这是 classes 和 C++ 中结构的唯一区别。因此,对于接口,使用结构更加自然。

问题二

不完全是。 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.h[=中声明的B三个方法未定义引用71=].

此外,B 需要知道如何从 A 派生,publicly、protected 或 private。

此外,在头文件中添加包含保护是个好主意,以防止编译器在编译像 a.ob.o 这样的目标文件时看到相同的类型声明两次:

#ifndef B_H
#define B_H

#include "a.h"

struct B : public A {
  ...
};

#endif

最后,static_method() 还需要 A 的实现,静态方法不能是虚拟的。

问题三

您不一定需要为 B 实现构造函数。如果您没有定义,编译器将为 B 生成一个默认构造函数。但是,如果您为 A 定义了一个非默认构造函数,则需要为 B 定义一个构造函数,以防您想要构造类型 B 的实例。构造函数可以在头文件中内联实现,也可以在b.cpp.

中定义