C++: Can't figure out how to hide implementation details properly - c++

I have the following setup:
foo.h:
class A {
friend class B;
private:
A() {}
};
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
vector<A> myMember;
};
An object of A will never be exposed to any program including foo.h. The vector with A's is only there to help B in its computation adapter role. By making A's constructor private, I thought I could avoid other compilation units from using it, and it seems to work. However, the problem is in
foo.cpp
void B::computeResult(Result &r) {
MyCustomStorage<A> storage;
A *a = storage.allocate(); // error: "A::A() is private"
}
where part of MyCustomStorage looks like so:
template <typename T>
class MyCustomStorage {
T *allocate() {
...
T *ptr = new T[count]; // error: "A::A() is private"
...
}
};
But I thought since allocate() is called from a member function, this wouldn´t happen! How could I solve this?
Making A a friend to MyCustomStorage seems very spaghetti-codish. Making A a private nested class of B makes all sorts of help-classes in foo.cpp fail because "A is private".
So what would be the cleanest way to solve this?
SOLUTION
I ended up going with #potatoswatter 's second solution, with these appropriate changes:
foo.h
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
class A {
private:
A() {}
};
class Helper; // forward declared!
vector<A> myMember;
};
foo.cpp
class B::Helper {
int help(A& a) { return 42; } // no problem! Helper is a member of B
}
void B::computeResult(Result &r) {
MyCustomStorage<A> storage;
A *a = storage.allocate(); // no problem! A is a member of B
Helper h;
h.help(*a); // no problem!
}

It's not the constructor of A that is private, it's the entire class.
The best solution is to create a "private" namespace. C++ doesn't have namespace-level access protection, but it's reasonable to expect that users won't access an unfamiliar namespace.
namespace impl {
struct A {
A() {}
};
}
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
vector<impl::A> myMember;
};
Another approach is to make A a member of B. This offers "real" access protection at the expense of deeper nesting. I personally prefer the first solution, and to avoid nested classes.
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
struct A {
A() {}
};
vector<A> myMember;
};
Any helpers that need A would then need to be friends. There are various workarounds like nesting A in a base class with protected access, but really, namespace impl offers the least compromises.

IMHO, You have a couple options. You can either 1) Use the Pimpl idiom, or, 2) you can use forward declaration.
Pimpl Idiom Example:
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
class Impl;
Impl *pimpl;
};
And in your *.cpp file, you can define the Impl class and use it's guts.
class B::Impl {
public:
std::vector<A> stuff;
}
B::B() : pimpl(new Impl) {
}
B::~B() {
delete pimpl;
}
void B::AddObject(Object &o) {
pimpl->stuff.Fx(o);
}
You can also use a smart pointer for the Pimpl idiom, I just didn't here for the sake of clarity/brevity.
Forward declaration can also be used if A is in the same namespace as B
class B {
public:
void addObject(Object &o); // adds to myMember; A is not exposed!
void computeResult(Result &r); // uses myMember to compute result
private:
std::vector<class A*> myMember;
};
But this idiom is fundamentally different than your requirements and restricts you to using a pointer within your object myMember, which you may not want to do. Inline defining class A* is also a non-standard forward-declarative approach. Of course, use of smart pointers would reduce the possibility of memory-leaks at this location.

Related

c++ Handle class circular reference problem

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 (e.g. Handle_Point2D) instead of the original classes (e.g. 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 (e.g. 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 internet 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
{
}

How to give access to public members with Pimpl?

pimpl.h
#include <memory>
class MyClassImpl;
class MyClass {
void Foo();
struct MyStruct {
int a;
int b;
} variable_struct;
private:
std::unique_ptr<MyClassImpl> m_pImpl;
};
pimpl.cpp
class MyClassImpl
{
public:
void DoStuff() { /*...*/ }
struct MyStructImpl {
int a;
int b;
} variable_struct_impl;
};
// MyClass (External/User interface)
MyClass::MyClass () : m_pImpl(new MyClassImpl()) { }
MyClass::~MyClass () = default;
void MyClass::Foo() {
m_pImpl->DoStuff();
}
How/What's the best practice to share a public member of the implementation to the Pimpl class (end user)?
What if they have a different name like in my example with struct MyStruct and struct MyStructImpl (variable_struct / variable_struct_impl)?
For methods, that's quite clear, we need to make the forward method anyway. (Foo() forwarded to DoStuff() in the example)
How to give access to public members with Pimpl?
You don't. The point of PIMPL is to hide all members of the Private IMPLementation, and having public access to them is entirely contrary to that point.
If you want pubic access, then don't put the member in a PIMPL.

"Illegal reference to non-static member" when trying to implement CRTP

I am trying to implement the curiously recurring template pattern (CRTP) to access a member variable of a child class from the parent class, but I am getting a compilation error saying I am illegally referencing a non-static member variable.
#include <iostream>
template <typename Child>
class Parent
{
public:
int get_value()
{
return Child::m_value;
}
virtual ~Parent() = default;
};
class Child : public Parent<Child>
{
int m_value = 42;
friend class Parent<Child>;
};
int main()
{
Child child;
std::cout << child.get_value() << std::endl;
}
Error:
illegal reference to non-static member 'Child::m_value'
How can I properly access the member variable of the child class from within the parent class?
Is CRTP even the best/cleanest approach here?
Here is the correct way to access members of a CRTP derived class.
template <typename Child>
class Parent
{
public:
int get_value()
{
// Do NOT use dynamic_cast<> here.
return static_cast<Child*>(this)->m_value;
}
~Parent() { /*...*/ }; // Note: a virtual destructor is not necessary,
// in any case, this is not the place to
// define it.
};
// A virtual destructor is not needed, unless you are planning to derive
// from ConcreteClass.
class ConcreteClass : public Parent<ConcreteClass>
{
friend class Parent<ConcreteClass>; // Needed if Parent needs access to
// private members of ConcreteClass
// If you plan to derive from ConcreteClass, this is where you need to declare
// the destructor as virtual. There is no ambiguity as to the base of
// ConcreteClass, so the static destructor of Parent<ConcreteClass> will
// always be called by the compiler when destoying a ConcreteClass object.
//
// Again: a virtual destructor at this stage is optional, and depends on
// your future plans for ConcreteClass.
public:
virtual ~ConcreteClass() {};
private:
int m_value;
};
// only ConcreteClass needs (optionally) a virtual destructor, and
// that's because your application will deal with ConcretClass objects
// and pointers, for example, the class below is totally unrelated to
// ConcreteClass, and no type-safe casting between the two is possible.
class SomeOtherClass : Parent<SomeOtherClass> { /* ... */ }
ConcreteClass obj1;
// The assignment below is no good, and leads to UB.
SomeOtherClass* p = reinterpret_cast<ConcreteClass*>(&obj1);
// This is also not possible, because the static_cast from
// Parent<UnrelatedClass>* to UnrelatedClass* will not compile.
// So, to keep your sanity, your application should never
// declare pointers to Parent<T>, hence there is never any
// need for a virtual destructor in Parent<>
class UnrelatedClass {/* ... */ };
auto obj2 = Parent<UnrelatedClass>{};
As the concrete type ConcreteClass and its relation to Parent is known ate compile-time, a static_cast is sufficient to convert this from Parent<ConcreteClass>* to a ConcreteClass*. This provides the same functionality as virtual functions without the overhead of a virtual function table, and indirect function calls.
[edit]
Just to be clear:
template <typename Child>
class Parent
{
public:
int get_value()
{
// the static cast below can compile if and only if
// Child and Parent<Child> are related. In the current
// scope, that's possible if and only if Parent<Child>
// is a base of Child, aka that the class aliased by Child
// was declared as:
// class X : public Parent<X> {};
//
// Note that it is important that the relation is declared
// as public, or static_cast<Child*>(this) will not compile.
//
// The static_cast<> will work correctly, even in the case of
// multiple inheritance. example:
//
// class A {];
// class B {};
// class C : public A
// , public Parent<C>
// , B
// {
// friend class Parent<C>;
// int m_value;
// };
//
// Will compile and run just fine.
return static_cast<Child*>(this)->m_value;
}
};
[edit]
If your class hierarchy gets a bit more complex, the dispatching of functions will look like this:
template <typename T>
class A
{
public:
int get_value()
{
return static_cast<T*>(this)->get_value_impl();
}
int get_area()
{
return static_cast<T*>(this)->get_area_impl();
}
};
template <typename T>
class B : public A<T>
{
friend A<T>;
protected:
int get_value_impl()
{
return value_;
}
int get_area_impl()
{
return value_ * value_;
}
private:
int value_;
};
template <typename T>
class C : public B<T>
{
// you must declare all bases in the hierarchy as friends.
friend A<T>;
friend B<T>;
protected:
// here, a call to C<T>::get_value_impl()
// will effetively call B<T>::get_value_impl(),
// as per usual rules.
// if you need to call functions from B, use the usual
// syntax
int get_area_impl()
{
return 2 * B<T>::get_value_impl();
}
};

How to expose the implementation only to a specified set of classes in the pimpl idiom?

Let's have a class A which has an inner class A::Impl. A class AllowedToAccess should be able to get A::Impl& from class A, no other class should be able to do that or even know that class A::Impl exists.
class A_1
{
public:
class Impl;
Impl& impl();
const Impl& impl() const;
private:
std::unique_ptr<Impl> m_impl;
};
class A_2
{
private:
friend class AllowedToAccess;
class Impl;
std::unique_ptr<Impl> m_impl;
};
class A_3
{
private:
friend class AllowedToAccess;
class Impl;
class ImplContainer
{
friend class A_3;
std::unique_ptr<Impl> impl;
} m_implContainer;
Impl& impl(); // return *m_implContainer.impl;
const Impl& impl() const; // return *m_implContainer.impl;
};
Here is some code to illustrate my ideas.
A_1
Pros: m_impl is secured.
Cons: classes not supposed to know about A::Impl will know about it (although they don't know what A::Impl really is about).
A_2
Pros: classes not supposed to know about A::Impl will not know about it.
Cons: m_impl is not secured (AllowedToAccess might just set it to nullptr).
A_3
Pros: classes not supposed to know about A::Impl will not know about it and m_impl is secured.
Cons: Boilerplate code for ImplContainer.
Any better ideas?
EDIT: Came up with a solution like this.
template <typename T>
class Accessor
{
private:
friend class AllowedToAccess;
typedef typename T::Impl impl_t;
static typename T::Impl& impl(T& t)
{
return *t.m_impl;
}
static const typename T::Impl& impl(const T& t)
{
return *t.m_impl;
}
};
class A
{
private:
friend class Accessor<A>;
class Impl;
std::unique_ptr<Impl> m_impl;
};
class A::Impl
{
public:
void f() const
{
}
};
class AllowedToAccess
{
public:
AllowedToAccess()
{
const A a;
const Accessor<A>::impl_t& impl = Accessor<A>::impl(a);
impl.f();
}
};
There is an implementation layer of code, and all those classes will be added as friends to Accessor.
And to further hide things the accessor would only be forward declared as template <typename T> class Accessor; in public code. And defined in private code.
If it is possible to move all logic that works with m_impl itself to a base class, you can make m_impl inaccessible to a derived class, but allow it to get a refernce to Impl, and then make Access class a friend of a derived class:
class Base {
protected:
class Impl;
Impl& impl();
private:
std::unique_ptr<Impl> m_impl;
};
class Base::Impl {
public:
Impl() {}
};
Base::Impl& Base::impl() { return *m_impl; }
class Derived : private Base {
public:
friend class Access;
Derived() {
auto& ptr = impl(); // ok
auto& ptr1 = m_impl; // error
}
};
class Access {
public:
Access(Derived& d) {
auto& ptr = d.impl(); // ok
auto& ptr1 = d.m_impl; // error
}
};
I don't know if its a better idea, but you could provide your own implementation of AllowedToAccess, that would safely expose needed interface. I call it Accessor.
class Base{
double priv = 0;
public:
friend class Accessor;
};
class Accessor {
public:
int& priv(Base& b) { return b.priv; };
};
Now classes can access exposed privates through Accessor. The semantics change a bit though because you use it like accessor.priv(b) = something but you have full control over the exposed interface. I think Accessor in this variation could have all static methods since the accessed object is passed always anyways. So the semantics would be Accessor::priv(b).
I guess it is a variation of your A_3 example, with code moved into the friend class. But it does not pollute A_ class.
Another option would be to provide your own Accessor class in form of a simple wrapper.
class Accessor {
public:
Accessor(Base b) _b(b);
int priv() { return _b.priv; };
int priv(int val) { _b.priv = val; };
int& priv_r() { return _b.priv; };
private:
Base& _b;
};
The interface here is also fully customizable, and you can access features like:
Base b;
Accessor interface(b);
interface.priv(42);
You can also make it absolutely safe disallowing to derive from Accessor (there are tricks for that), so no-one can derive and screw up your objects via an evil implementation of the Accessor. I think it would be a little bit paranoid though.
How about this:
class A_4
{
public:
class Impl;
Impl& impl();
const Impl& impl() const;
private:
std::unique_ptr<Impl> m_impl;
};
class A_4::Impl
{
private:
friend class A_4;
friend class AllowedToAccess;
Impl();
~Impl();
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
// All members private!
};
It doesn't matter that code can call impl() or write A_4::Impl if there's nothing useful they can actually do with it.

Solving cross referencing

I have a problem creating some form of hierarchy with different object types. I have a class which has a member of another class, like this:
class A
{
public:
A(){}
~A(){}
void addB(B* dep){
child = dep;
dep->addOwner(this);
}
void updateChild(){
child->printOwner();
}
void print(){
printf("Printing...");
}
private:
B* child;
};
And this is class B:
class B
{
public:
void addOwner(A* owner){
ownerObject = owner;
}
//ISNT WORKING
void printOwner(){
ownerObject->print();
}
private:
A* ownerObject;
};
Calling a function of "B" out of class "A" works just fine but trying it vice versa gives a compiler error because A is not defined in B. It actually is by using an include and a forward declaration, but I guess its a cross reference problem which the compiler can not solve.
Is there any chance to solve this problem or should I rethink my design?
You say that you already solved your circular dependency problem by using a forward declaration of A instead of including the header where A is defined, so you already know how to avoid circular includes. However, you should be aware of what is possible and what is not with incomplete types (i.e. types that have been forward declared).
In your case, you try to call the member function print on an object that has an incomplete type; the compiler knows nothing about this type excepts that it will be defined at some point, so it does not allow you to do this. The solution is to remove the implementation of the printOwner member function from the B header and put it into an implementation file:
//B.hpp
class A; // forward declaration
class B
{
public:
void addOwner(A* owner);
void printOwner() const; // I think this member function could be const
private:
A* ownerObject;
};
//B.cpp
#include "B.hpp"
#include "A.hpp" // here we "import" the definition of A
void B::addOwner(A * owner)
{
ownerObject = owner;
}
void B::printOwner() const
{
ownerObject->print(); //A is complete now, so we can use its member functions
}
You could possibly do the same thing in the A header.
You can use forward declaration, and define the member functions outside of the class, i.e.
// A.h
class B;
class A { public:
void addB(B* dep); // don't define addB here.
...
};
// B.h
class A;
class B { public:
void addOwner(A* owner); // don't define addOwner here.
...
};
// A.cpp
#include "A.h"
#include "B.h"
void A::addB(B* dep) {
...
}
// B.cpp
// similar.
You probably should rethink your design, since a crcular parent-child relationship is usually a code smell.
But, you can make the compiler happy :
#include <cstdlib>
#include <cstdio>
class A
{
public:
A(){}
~A(){}
void addB(class B* dep);
void updateChild();
void print(){
printf("Printing...");
}
private:
class B* child;
};
class B
{
public:
void addOwner(A* owner){
ownerObject = owner;
}
//ISNT WORKING
void printOwner(){
ownerObject->print();
}
private:
A* ownerObject;
};
void A::addB(class B* dep){
child = dep;
dep->addOwner(this);
}
void A::updateChild(){
child->printOwner();
}
int main()
{
return 0;
}
You should move B::printOwner implementation to .cpp file.