【问题标题】:C++ Interface Implementation and Subclassed Object InstatiationC++ 接口实现和子类对象实例化
【发布时间】:2018-07-03 18:54:59
【问题描述】:

更新 实际情况是我需要创建一个包以提交给 NIST,试图测试我正在研究的面部识别算法。要使用的 API 可以在 NIST API 找到,git 的项目在 git project

一些代码来总结一下场景:

a.h - 接口 A,由纯虚方法和一个静态方法组成(NIST 项目的 frvt11.h)

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;
}

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

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

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

【问题讨论】:

  • 你的意思是class B : public A?旁注,您应该熟悉并使用 override 关键字
  • 仅当您打算多态地使用接口时,才需要接口 A。有了 main 函数作为你的存在,A 根本没有存在的理由。
  • @CoryKramer 我不明白你的问题,但我想做的是实现接口 A 方法,将其称为 B 类,并在主函数中使用这些实现的方法。我会看看 override 关键字,谢谢。
  • @CarlosOst 将接口声明为struct 更顺利。
  • 感谢弗兰克的评论。我看到在这个例子中确实没有必要,但是搜索这个主题我发现了一些案例,你是对的。

标签: c++ inheritance subclassing


【解决方案1】:

问题 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。例如,如果还没有A 的声明,编译器将如何检查override 关键字。如果您没有任何重写的虚拟方法,则仍然需要知道 A,因为编译器需要能够推断出 B 的大小。

此外,如 cmets 中所述,将 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.h中声明的B的三个方法的未定义引用。

此外,B 需要知道如何从 A 派生,无论是公开的、受保护的还是私有的。

此外,最好在头文件中添加包含保护,以防止编译器在编译 a.ob.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中定义。

【讨论】:

  • 谢谢@TonvandenHeuvel。它没有解决我的问题,但你的回答对我来说已经足够了。它没有解决我的问题,因为实际的上下文有一些我没有在这里澄清的细微差别。这是我的错,不是你的。
【解决方案2】:

问题 1。

您可以使用工厂模式,那么您只能在 Factoru 文件中添加 b.h 吗?并返回指向 A 类的指针或智能指针。例如,它可以是工厂函数,如:

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 类构造函数。

【讨论】:

    猜你喜欢
    • 2013-03-13
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    • 2014-08-18
    • 2012-01-22
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    相关资源
    最近更新 更多