[英]c++ Handle class circular reference problem
我不确定我的问题标题是否正确和清楚。 我不是一个非常有经验的软件工程师。
我一直在准备一个 3D 几何库,它使用句柄,因为我不想使用删除运算符或智能指针。 我有一些类涉及到 class 层次结构(实现继承):ReferenceBase、PointBase、Point2D、Point3D、VectorBase 等。例如,CoordSystem 继承自 GeometryBase,PointBase 继承自 ReferenceBase,LinePieceBase 继承自 GeometryBase。 我为每个对象都有相应的句柄类:Handle_GeometryBase、Handle_Point2D、Handle_Plane 等。我使用句柄对象(例如 Handle_Point2D)而不是原始类(例如 Point2D)实现了库。 例如平面 class 的项目点方法定义如下:
Handle_Point3D Plane::project(const Handle_PointBase& point) {}
句柄类反映了相同的层次结构(例如 Handle_VectorBase 继承自 Handle_ReferenceBase)。 由于这个 inheritance,我无法使用通用的 class 作为句柄。因此,我使用宏为每个原始 class 定义了一个句柄 class。 句柄类几乎相同接受一些细节,所以我定义了三个宏。
这是我的架构:
// Forward declarations for the handle classes
class Handle_Foo;
class Handle_Bar;
class Foo {
int a;
public:
Foo(int aa) : a{ aa } {}
/* copy/move ctors, assignments and dtor */
};
class Bar {
Handle_Foo f;
public:
Bar(const Handle_Foo& ff) : f{ ff } {}
/* copy/move ctors, assignments and dtor */
};
class Handle_Foo {
Foo* p;
public:
Handle_Foo() : p{} {}
Handle_Foo(Foo* pp) : p{ pp } {}
Handle_Foo(const Handle_Foo& rhs) : p{ new Foo{ *rhs.p } } {};
Handle_Foo(Handle_Foo&& rhs) noexcept : p{ rhs.p } { delete rhs.p; }
Handle_Foo& operator=(const Handle_Foo& rhs) {
p = new Foo{ *rhs.p };
return *this;
};
Handle_Foo& operator=(Handle_Foo&& rhs) noexcept {
p = rhs.p;
delete rhs.p;
return *this;
}
Foo* operator->() const { return p; }
~Handle_Foo() { delete p; }
Foo* Get() const noexcept { return p; }
void Set(Foo* pp) noexcept { p = pp; }
bool IsNull() const noexcept { return bool(p == nullptr); }
};
class Handle_Bar {
Bar* p;
public:
Handle_Bar() : p{} {}
Handle_Bar(Bar* pp) : p{ pp } {}
Handle_Bar(const Handle_Bar& rhs) : p{ new Bar{ *rhs.p } } {};
Handle_Bar(Handle_Bar&& rhs) noexcept : p{ rhs.p } { delete rhs.p; }
Handle_Bar& operator=(const Handle_Bar& rhs) {
p = new Bar{ *rhs.p };
return *this;
};
Handle_Bar& operator=(Handle_Bar&& rhs) noexcept {
p = rhs.p;
delete rhs.p;
return *this;
}
Bar* operator->() const { return p; }
~Handle_Bar() { delete p; }
Bar* Get() const noexcept { return p; }
void Set(Bar* pp) noexcept { p = pp; }
bool IsNull() const noexcept { return bool(p == nullptr); }
};
因此,如您所见,原始类需要定义句柄类。
我在 inte.net 或 Stroustrup 的书中(c++ 编程语言)看到的句柄示例是使用调用默认复制和移动 ctors 以及默认 dtor 的模板定义的。
// Handle copy ctor for a template design
template<class T>
class Handle {
T* p;
public:
Handle(const Handle& rhs) : p{ new T{ *rhs.p } } {};
/* Other code */
};
但是,我的体系结构需要定义 ctors、dtor 和赋值运算符。
// Handle copy ctor for my current design
class Handle_Bar {
Bar* p;
public:
Handle_Bar(const Handle_Bar& rhs) : p{ new Bar{ *rhs.p } } {};
/* Other code */
};
由于p{ new Bar{ *rhs.p } }
,复制构造函数需要定义 Bar class 的复制构造函数。
总之,原始类需要句柄类的定义,而句柄类需要为原始类定义复制/移动函数、asssinments 和 dtor。
对于此设计模式,我收到了 Bar class 中定义的 (Handle_Foo f) 成员的以下错误:
f 使用未定义的 class Handle_Foo
以前我有不同的模式。 我在另一个 header 文件中定义了句柄类,例如
句柄.h:
// Forward declarations for the original classes
class Foo;
class bar;
/* The same definitions for the handle classes as above */
几何.h
#include "Handles.h"
/* Definitions for the original clasases */
在这种情况下,原始的 class 定义有效,但对于句柄类的复制/移动 ctors/assignments 和 dtor,我收到了错误。
在过去,我使用了一个框架(Caesam),它使用为每个 object 定义的句柄类,效果很好。 但是框架的实现不是开源的。 因此,我无法获得他们使用的架构。
因此,我该如何解决上面提到的错误:
Error: f uses undefined class Handle_Foo
我已经解决了这个问题。 我使用 Caesam 的框架实际上使用 OpenCascade (OCCT) 库作为句柄。 OCCT 可以从https://www.opencascade.com/下载。 本视频介绍了 OCCT 的 VS 配置过程。 handle的定义和实现如下:
// The header file: Foo.hxx
#ifndef _Foo_HeaderFile
#define _Foo_HeaderFile
#ifndef _Standard_HeaderFile
#include <Standard.hxx>
#endif
#ifndef _Standard_Handle_HeaderFile
#include <Standard_Handle.hxx>
#endif
#ifndef _Standard_Type_HeaderFile
#include <Standard_Type.hxx>
#endif
#ifndef _Standard_Size_HeaderFile
#include <Standard_Size.hxx>
#endif
#ifndef _Standard_Transient_HeaderFile
#include <Standard_Transient.hxx>
#endif
#ifndef _FooBase_HeaderFile
#include "FooBase.hxx"
#endif
// Forward declaration of the class and the base class
class Foo;
class FooBase;
// Define the handle
DEFINE_STANDARD_HANDLE(Foo, FooBase)
class Foo: public FooBase
{
// Define the members, ctors, dtor and operators
// Define the RTTI
public:
DEFINE_STANDARD_RTTIEXT(Foo, FooBase)
}
#endif
所有类都可以类似地定义。 RTTI 的实现应该在所有的定义完成之后进行。 因此,最好在 cxx 文件中执行 RTTI 实现。
// Foo.cxx
#include "Foo.hxx"
// Define RTTI
IMPLEMENT_STANDARD_RTTIEXT(Foo, FooBase)
// Implement the functions
Standard_Transient 是 OCCT 的基础 class。 最好为您的项目创建一个抽象基础 class 继承自 Standard_Transient
class AbstractBase : public Standard_Transient
{
}
class foo: public AbstractBase
{
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.