I am not sure if the title of my question is correct and clear enough. I am not a very experienced software engineer.
I have been preparing a 3D geometry library which utilizes handles as i dont want to use either delete operators or smart pointers. I have a number of classes which are involved in a class hierarchy (implementation inheritance): ReferenceBase, PointBase, Point2D, Point3D, VectorBase etc. For example, CoordSystem inherits from GeometryBase, PointBase inherits from ReferenceBase and LinePieceBase inherits from GeometryBase. I have corresponding handle classes for each: Handle_GeometryBase, Handle_Point2D, Handle_Plane etc. I implemented the library using handle objects (eg Handle_Point2D) instead of the original classes (eg Point2D). For example the project point method of Plane class is defined like:
Handle_Point3D Plane::project(const Handle_PointBase& point) {}
The handle classes have the same hierarchy reflected (eg Handle_VectorBase inherits from Handle_ReferenceBase). I could not utilize a generic class for the handles because of this inheritance. So, i have defined a handle class for each original class using macros. The handle classes are almost the same accept for a few details so i have defined three macros.
This is the architecture i have:
// 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); }
};
So the original classes requires the handle classes to be defined as you see.
The handle examples i saw on the inte.net or in the Stroustrup's book (c++ programming language) is defined with a template which calls the default copy and move ctors and the default 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 */
};
However, my architecture requires the ctors, dtor and assignment operators to be defined.
// 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 */
};
The copy ctor requires the copy ctor of Bar class to be defined due to p{ new Bar{ *rhs.p } }
.
In summary, the original classes require the definition for the handle classes and the handle classes require the definition of copy/move ctors, asssinments and dtor for the original classes.
For this design pattern i recive the following error for the (Handle_Foo f) member defined in Bar class:
f uses undefined class Handle_Foo
Previously i had a different pattern. I have defined the handle classes in another header file like
Handles.h:
// Forward declarations for the original classes
class Foo;
class bar;
/* The same definitions for the handle classes as above */
Geometry.h
#include "Handles.h"
/* Definitions for the original clasases */
In this case, the original class definitions worked but for the copy/move ctors/assignments and dtor of the handle classes i recieved errors.
In the past i used a framework (Caesam) which used handle classes defined for each object which worked well. But the implementaation of the framework is not open source. Hence, i could not get the architecture they used.
Hence, how can i solve the error i mentioned above:
Error: f uses undefined class Handle_Foo
I have solved the problem. The framework I used Caesam actually uses OpenCascade (OCCT) library for the handles. OCCT can be downloaded from https://www.opencascade.com/ . VS configuration procedure for OCCT is described in this video . Defining and implementation of a handle is as follows:
// 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
All classes can be defined similarly. The implementation of RTTI should be performed after all definitions are done. So, its better to do RTTI implementation in cxx files.
// Foo.cxx
#include "Foo.hxx"
// Define RTTI
IMPLEMENT_STANDARD_RTTIEXT(Foo, FooBase)
// Implement the functions
Standard_Transient is the base class for the OCCT. Its better to create an abstract base class for your project inheritting from Standard_Transient
class AbstractBase : public Standard_Transient
{
}
class foo: public AbstractBase
{
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.