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.o
或 b.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.
中定义
更新 实际情况是我需要创建一个包以提交给 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.o
或 b.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.