繁体   English   中英

c++ 处理class循环引用问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM