Circular inclusion with Parent, Child and Other - c++

so I just can't work out my circular inclusions. Can anyone give me a hand? I know I need to be pre-declaring my classes, but I can not work out the combination (mostly guess-work though). OtherClass is meant to be like a container for ParentClass and its children.
My current class setup is along the lines of this:
OtherClass.h
class ParentClass; // includes
class ChildClass;
class OtherClass
{
ParentClass* parent;
ChildClass* child;
}
ParentClass.h
class OtherClass;
class ParentClass
{
OtherClass* other;
}
ChildClass.h
#include "ParentClass.h";
#include "OtherClass.h";
class ChildClass: public ParentClass
{
other->foo(); // Using OtherClass pointer declared in parent.
}
For that approach above, I am getting Member access into incomplete type 'ParentClass'.
This probably also needs to be expandable, as I'm sure in the future there will be more child classes of ChildClass.

It's not clear what you mean by ChildClass.cpp uses things from OtherClass as well, that is, if you want to inherit from the OtherClass type or just compose of it ('has a' vs. 'is a'), but you could use templates as well to make it a generic container class for various types:
OtherClass.h
#if !defined(OTHER_CLASS_HPP)
#define OTHER_CLASS_HPP
template < typename T1, typename T2 >
class OtherClass
{
public: // private/protected ??
T1* parent;
T2* child;
void foo()
{
this->parent->bar();
this->child->baz();
// this->parent->baz(); // compile error since no ParentClass::baz
}
};
#endif
ParentClass.h
#if !defined(PARENT_CLASS_HPP)
#define PARENT_CLASS_HPP
#include "OtherClass.h"
template < typename T1 >
class ParentClass
{
public:
ParentClass() : other(new OtherClass<ParentClass, T1>) {}
~ParentClass() { delete this->other; }
void bar() { }
protected:
OtherClass<ParentClass, T1>* other;
};
#endif
ChildClass.h
#if !defined(CHILD_CLASS_HPP)
#define CHILD_CLASS_HPP
#include "ParentClass.h"
class ChildClass : public ParentClass < ChildClass >
{
public:
void foo()
{
this->other->foo();
}
void baz() { }
};
#endif
And depending on what each class exactly does, this can abstract a little more for you to make it 'expandable'. You don't have to forward declare anything with this approach but it can add complexity elsewhere (again, depending on the exact needs of the parent/child relationship/classes).
Hope that can help.

Related

How can I offload dependency injected template class providing templated functions to pimpl class

I have an application class that can take in a dependent class as a template argument to the constructor. This dependent class is required to provide certain templated functions that the application class can call. I would like to offload this dependent class object to a pimpl class so the application class is not a template class and thus header-only.
Here is a rough idea of what I mean.
///////////
// impl.h
///////////
template<typename Helper>
struct Impl
{
public:
Impl(Helper& helper) : helper_(helper)
{
}
template <typename T>
void someHelperFn1(T t)
{
helper_->fn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return helper_->fn2();
}
private:
Helper& helper_;
};
///////////
// app.h
///////////
#include "impl.h"
class App
{
public:
template<typename Helper>
App(Helper &h) :impl_(new Impl) {}
template <typename T>
void someHelperFn1(T t)
{
impl_->someHelperFn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return impl_->someHelperFn2();
}
void someAppFn();
private;
std::unique_ptr<Impl> impl_;
};
///////////
// app.cpp
///////////
void App::someAppFn()
{
// some useful code
}
I realize the above code doesn't compile since Impl is really a template class and so App would also be a template class too. That is what I would like to avoid so that App is not a header-only class. I found something similar except the functions that I want to call from the helper dependency are template functions and they are not in this case. It seemed pretty close otherwise to what I wanted to do.
Any ideas on how I can avoid making App a template class?
I tried making the helper class use a common base class but that is not really possible with the template functions.
Also, note that I am limited to C++ 17 for the compiler.
You will need to make sure the public header file (the one with the class that has the pimpl pointer) doesn't expose the header file only class template of the implementation. Use an interface for that like this.
I did not dependency inject the implementation because that should not be needed.
#include <memory>
#include <iostream>
// public header file
// for pimpl pattern I often use an interface
// (also useful for unit testing later)
class PublicItf
{
public:
virtual void do_something() = 0;
virtual ~PublicItf() = default;
protected:
PublicItf() = default;
};
// the public class implements this interface
// and the pimpl pointer points to the same interface
// added advantage you will have compile time checking that
// the impl class will all the methods too.
class PublicClass final :
public PublicItf
{
public:
PublicClass();
virtual ~PublicClass() = default;
void do_something() override;
private:
std::unique_ptr<PublicItf> m_pimpl; // the interface decouples from the template implementation (header file only)
};
// private header file
// this can now be a template
template<typename type_t>
class ImplClass final :
public PublicItf
{
public:
void do_something() override
{
m_value++;
std::cout << m_value << "\n";
}
private:
type_t m_value{};
};
// C++ file for Public class
// inlcude public header and impl header (template)
PublicClass::PublicClass() :
m_pimpl{ std::make_unique<ImplClass<int>>() }
{
};
void PublicClass::do_something()
{
m_pimpl->do_something();
}
// main C++ file
int main()
{
PublicClass obj;
obj.do_something();
return 0;
}

can't find overloaded method from inherited class template

This is the first time I am using class templates so please don't be to harsh if I made a simply mistake.
I have a class template class A<class T>. It has a method init() that is pure virtual and therefore will be implemented separately in every derived class. What all these possible derived classes will have in common is an init(T* i_x) which basically does some general stuff and then calls the init(). Because this will be the same for every derived class I want to define it in the base class template already. But somehow my compiler doesn't find the right function.
If I try to use the init(T* i_x) on an object of a derived class A_der I get the error:
no matching function for call to 'A_der::init(B_der*)
The classes used for the template parameter T will all be derived from another class B. Therefore the error message involves the class B_der which is derived from class B.
I boiled the problem down to a small example, which should involve everything that is important for the problem. If I try to compile this example in Visual Studio (normally I work in STM32CubeIDE) I get the following error
Severity Code Description Project File Line Suppression State
Error C2660 'A_der::init': function does not take 1
arguments template_class-overload_inherited_method [...]\main.cpp 8
So somehow the only function the compiler finds at this point is init() but not the base class template method init(T* ).
Can somebody please tell me why it is like that and what can I do to get the behaviour I want (without implementing a similar init(T* ) in every derived class of A?
Here is my example code:
base class template A - declaration - A.hpp
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
base class template A - implementation - A.cpp
#include "A.hpp"
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derived class A_der
#include "A.hpp"
#include "B_der.hpp"
#pragma once
class A_der : public A<B_der>
{
void init() override;
};
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
For the sake of completeness:
class B
{
};
class B_der : public B
{
};
EDIT - Solved
Thanks a lot for the fast replies.
The combination of the comments from #BoP and #Jarod42 solved the problem.
I had to unhide the method with using A<B_der>::init (actually renaming might be the more elegant way) and move the implementation of A into A.hpp.
I will offer the updated example which builds successfully with Visual Studio 2019 for me here:
base class A
template<class T>
class A
{
protected:
T* m_x;
public:
virtual void connect(T* i_x) final;
virtual void init() = 0;
virtual void init(T* i_x) final;
};
template<class T>
void A<T>::connect(T* i_x)
{
//some checks
m_x = i_x; //connects object of B to A
}
template<class T>
void A<T>::init(T* i_x)
{
connect(i_x);
init();
}
derivad class A_der
A_der.hpp
#include "A.hpp"
#include "B_der.hpp"
class A_der : public A<B_der>
{
public:
void init() override;
using A<B_der>::init;
};
A_der.cpp
#include "A_der.hpp"
void A_der::init()
{
//Initialization which needs a B_der connected already
}
main.cpp
#include "B_der.hpp"
#include "A_der.hpp"
int main(void)
{
B_der testB;
A_der testA;
testA.init(&testB);
return 0;
}
for completeness
B.hpp
class B
{
};
B_der.hpp
#include "B.hpp"
class B_der : public B
{
};
I also forgot to make the methods of A_der public in the earlier example, this is corrected here. And I removed the #pragma onces in this example.
class A_der : public A<B_der>
{
void init() override;
};
When you declare a function init in the derived class, it hides all things named init from the base class. This is just like when declaring something in an inner scope - it hides things with the same name from outer scopes.
There are ways to import the hidden names, but an easy solution would be to just chose a different name, like init_base. Or, probably better, pass a parameter to the class constructor.

get return type from a function of a class that was forward-ed declaraion

Is it possible to get return type UglyIterator<> of a function of a class B::f which is forward declaration?
Example
MyArray is a class that acts like std::vector.
Its begin() and end() function return a ugly type.
template<class T> class MyArray{
UglyIterator<Protocol1,Protocol2,SafetyFlag,brabrabra> begin(){
//some code
}
//... other functions ....
};
B has MyArray<int> as a value field.
With the magic of auto-keyword, B can pretend to be a neat class.
#include "MyArray.h"
class B{ //just a bundle of data
MyArray<int> bField;
public: auto f(){ //<--- neat
return bField.begin();
}
//... other fields ...
};
Manager is a manager of B and do other things.
#include "B.h"
class Manager{ //just a bundle of data
decltype(&B::f) mField; //I can cache it, so neat!
//^ actually it is "UglyIterator<Protocol1,Protocol2,SafetyFlag,brabrabra>"
//... other functions/fields ...
};
As project grow, I noticed that Manager.h was included in many files, and MyArray's code changed very often.
To reduce compile time, I decided to forward declaration at Manager.
I changed mField to mFieldPtr, but I get compile error :-
class B;
class Manager{
std::unique_ptr<std::result_of<decltype(&B::f)>::type> mFieldPtr;
//^ should compile error (can not recognize "B::f")
//... other functions ...
};
How to get the return type decltype(&B::f) elegantly?
My workaround
Create a new file B_TopHeader.h.
using B_F_returnType = UglyIterator<Protocol1,Protocol2,SafetyFlag,brabrabra>;
//^ the type "UglyIterator" also need another forward declaration
Then let the Manager #include B_TopHeader.h instead :-
#include "B_TopHeader.h"
class Manager{
std::unique_ptr< B_F_returnType > mFieldPtr;
//... other functions ...
};
However, I think it is not elegant. It seems to be a hack.
I have to forward the return type manually.
You may use Pimpl idiom to hide the dependency, something like:
class Manager
{
public:
~Manager() noexcept; // you certainly have also to handle copy/move
// Stuff using mFieldPtr, but which doesn't return it.
private:
std::unique_ptr<struct Impl> mImpl;
};
And in cpp
#include "Manager.h"
#include "B.h"
struct Manager::Impl
{
// Implementation using mField
decltype(&B::f) mField;
};
Manager::~Manager() noexcept = default;
// Forward methods of `Manager` to `Impl`.

C++: How to restrict a class template, to a class derived from a pure virtual base

I want to call a method on a template class, and I need a way to ensure that method will be on my template class.
The only way I know how to ensure a method is available on a class, is to derive the class from a pure virtual base class. This creates an enormous amount of overhead, as you can see in the code below.
Obviously, the interface is extraneous and unrelated to the explicit specialization of the templated class, which is actually driving the code in main.cpp. Am I just being old fashioned and clinging onto "interfaces", or is there a modern object-oriented approach to ensuring template classes are complete?
EDIT:
To provide insight into the code below...
There is an interface, called "Interface", which has a virtual destructor and a pure virtual method called sayHi(). A inherits from Interface and implements sayHi(). A is then passed as a template into Template, which then calls sayHi() in its salutations() method. To further confuse things, a static method is the best solution for my problem. However, in order to use a base class as an interface to provide inheritance to my template class I could not have a static method, so you see two methods non-static to satisfy the virtual method and one static to satisfy my needs.
As I see it, there is no need of the interface other than to be organized in an object oriented since, and it causes a considerable amount of pain. Is there another way to get the sense of order provided by an interface, or is this type of thinking just obsolete?
main.cpp
#include "a.h"
#include "template.h"
int main (int argc, char * argv[]) {
Template<A> a;
a.salutations();
return 0;
}
interface.h
#ifndef INTERFACE_H
#define INTERFACE_H
struct Interface {
virtual
~Interface (
void
) {}
virtual
void
sayHi (
void
) const = 0;
};
#endif
a.h
#ifndef A_H
#define A_H
#include "interface.h"
class A : public Interface {
public:
A (
void
);
~A (
void
);
void
sayHi (
void
) const;
static
void
sayHi (
bool = false
);
};
#endif
a.cpp
#include "a.h"
#include <iostream>
A::A (
void
) {}
A::~A (
void
) {}
void
A::sayHi (
void
) const {
return A::sayHi(true);
}
void
A::sayHi (
bool
) {
std::cout << "Hi from A!" << std::endl;
}
template.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
template <class Interface>
class Template {
public:
void salutations (void);
};
#endif
template.cpp
#include "template.h"
#include "a.h"
template<>
void
Template<A>::salutations (
void
) {
A::sayHi();
return;
}
C++ is not Java. I do not know any way to say that the class or typename must be derived from another class.
It is really duck typing. Just use the methods and compiler will throw errors if they are not present. BTW, when you write
template <class Interface>
class Template {
public:
void salutations (void);
};
Interface is here the same as T would be : it does not require that the specialization used will be a subclass of class Interface.

C++ Can a class pass itself by reference?

Trying to pass a parent class object to a child class object so that the child class object has control over the parent class object's methods.
This is however resulting in header related issues.
I've tried forward declaring one of the classes but it seems whatever class is declared first always has trouble reading from the class declared below.
Both errors refer to Device' constructor where try to call dm's hello world method, they are:
Use of undefined type 'DeviceManager'
Left of '->HelloWorld' must point to class/struct/union/generic type
...
//main.cpp
#include "parent.h"
void main()
{
cout << "Created DeviceManager\n";
DeviceManager* deviceManager = 0;
deviceManager = new DeviceManager;
cout << "Giving DeviceManager a device\n";
deviceManager->p = new Device(deviceManager);
cout << "Giving Device a reference to DevicenManager\n";
deviceManager->Share();
}
...
class DeviceManager;
class Device
{
public:
Device(DeviceManager* manager)
{
dm = 0;
this->dm = manager;
this->dm->HelloWorld();
}
DeviceManager* dm;
};
//device manager
class DeviceManager
{
public:
DeviceManager()
{
p = 0;
}
void HelloWorld()
{
//if this calls we know the child has control over the parent.
cout << "Hello World";
}
Device* p;
};
Yes.
To solve circular dependencies with class member and function declarations, you can forward-declare a class:
class A;
class B {
A *a;
};
class A {
B *b;
};
To define class member functions that access members of the other class, you must define the function after the other class has been defined:
class B;
class A {
public:
void f(B &arg);
};
class B {
public:
void g(A &arg);
};
void A::f(B &arg) {
arg.g(*this);
}
void B::g(A &arg) {
arg.f(*this);
}
Usually, in a C++ project, you wouldn't even encounter this problem: You would put function definitions, i.e. implementations, into .cpp files, while putting the class definitions into header files. Class forward declarations, if neccesary, could be put into their own header files that are included by all headers that need them.
A full example of how you would split the above code into multiple files:
a.cpp
#include "a.h"
#include "b.h"
void A::f(B &arg) {
arg.g(*this);
}
b.cpp
#include "b.h"
#include "a.h"
void B::g(A &arg) {
arg.f(*this);
}
a.h
#ifndef _A_H_
#define _A_H_
#include "forward_declarations.h"
class A {
public:
void f(B &arg);
};
#endif //_A_H_
b.h
#ifndef _B_H_
#define _B_H_
#include "forward_declarations.h"
class B {
public:
void g(A &arg);
};
#endif //_B_H_
forward_declarations.h
#ifndef _FORWARD_DECLARATIONS_H_
#define _FORWARD_DECLARATIONS_H_
class A;
class B;
#endif //_FORWARD_DECLARATIONS_H_
As a general rule of thumb, if you need to forward-declare a class, you might have misdesigned something and should think about whether there is a better way (but there also are perfectly valid use cases that require class forward declarations).
If you don't understand my #ifndef, #define and #endif preprocessor lines: These are header guards, and should be used with all files that are included somewhere else, exception you know precisely what you're doing. Believe me. You'll regret ommiting one.
If your problem is cyclic dependancy, like this:
// DeviceManager.h
#include "device.h"
class DeviceManager
{
DeviceManager(Device& device) {}
};
// Device.h
#include "DeviceManager.h"
class Device
{
Device(DeviceManager& manager) {}
};
You can solve the problem be forward declaring one of the classes, and passing the object by pointer.
// Device.h
//#include "DeviceManager.h"
class DeviceManager;
class Device
{
Device(DeviceManager* manager) {}
};