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.
Related
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;
}
So, i've been working in a project of a System API, and i'm trying to figure out how to avoid circular dependency in the definition of a static template method. The thing is, template methods cannot be defined in a separeted cpp, and i cannot define it in the header file either because that would cause circular dependency:
flow.h:
#include "system.h"
#include "flowImpl.h" //circular dependency
#include <vector>
#ifndef TRAB_INDIVIDUAL_FLOW_H
#define TRAB_INDIVIDUAL_FLOW_H
typedef std::vector<System*>::iterator SystemIterator;
class Flow {
public:
//-----------------------------------
//What's giving me problems
template <typename T_FLOW_IMPL>
static Flow* createFlow() {
return FlowImpl::createFlow<T_FLOW_IMPL>();
}
template <typename T_FLOW_IMPL>
static Flow* createFlow(System* s1,System* s2,std::string str) {
return FlowImpl::createFlow<T_FLOW_IMPL>(s1,s2,str);
}
//-----------------------------------
virtual double executeFunction()=0;
virtual System* getTargetSys()=0;
virtual System* getSourceSys()=0;
virtual std::string getName()=0;
virtual void changeTargetSys(SystemIterator)=0;
virtual void changeSourceSys(SystemIterator)=0;
virtual void changeTargetSys(System*)=0;
virtual void changeSourceSys(System*)=0;
};
#endif
flowImpl.h
#include "flow.h"
#ifndef TRAB_INDIVIDUAL_FLOWIMPL_H
#define TRAB_INDIVIDUAL_FLOWIMPL_H
class ModelImpl;
class FlowImpl : public Flow {
friend ModelImpl;
friend Flow;
private:
FlowImpl();
FlowImpl(System*,System*,std::string);
FlowImpl(Flow*,std::string);
std::string name;
System* source_sys;
System* target_sys;
template <typename T_FLOW_IMPL>
static Flow* createFlow() {
Flow* f = new T_FLOW_IMPL();
return f;
}
template <typename T_FLOW_IMPL>
static Flow* createFlow(System*,System*,std::string) {
Flow* f = new T_FLOW_IMPL(s1,s2,str);
return f;
}
protected:
double getSourceQ();
double getTargetQ();
public:
virtual ~FlowImpl();
bool operator==(FlowImpl&);
FlowImpl& operator=(const FlowImpl&);
virtual double executeFunction()=0;
System* getTargetSys() override;
System* getSourceSys() override;
std::string getName() override;
void changeTargetSys(SystemIterator) override;
void changeSourceSys(SystemIterator) override;
void changeTargetSys(System*) override;
void changeSourceSys(System*) override;
};
#endif
I tried using forward declaration, but with no success, because i cannot forward declare a method of another class (being FlowImpl::createFlow()), only the entire class.
My objective in those static methods are to make a Method Factory with static members using interfaces, and since i cannot use "virtual" for static template methods, my only option was to implement it on the interface, and inside the implementation call the same static method but for the subclass, which have the atributes for allocation. As I said, I cannot do that either because template methods can't be implemented in a different file, and if I define it inside the header it will cause circular dependency with "flowImpl.h".
Thanks for reading! Any ambiguities or lack of information please report so i can clarify it.
Remove the #include of flowImpl.h from flow.h, and forward-declare the template class method:
class Flow {
public:
// ...
template <typename T_FLOW_IMPL>
static Flow* createFlow();
Then finish the job in flowImpl.h, after the implementation class's declaration:
class flowImpl {
// ...
};
template <typename T_FLOW_IMPL>
static Flow* Flow::createFlow() {
return FlowImpl::createFlow<T_FLOW_IMPL>();
}
Do the same for the other template method, as well. Note that whatever needs to call these class methods will have to include the flowImpl.h header file, though.
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.
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.
Very new to c++ having trouble calling a function from another class.
Class B inherits from Class A, and I want class A to be able to call a function created in class B.
using namespace std;
class B;
class A
{
public:
void CallFunction ()
{
B b;
b.bFunction();
}
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
It all looks fine on screen (no obvious errors) but when I try to compile it i get an error C2079 'b' uses undefined class B.
I've tried making them pointers/ friends but I'm getting the same error.
void CallFunction ()
{ // <----- At this point the compiler knows
// nothing about the members of B.
B b;
b.bFunction();
}
This happens for the same reason that functions in C cannot call each other without at least one of them being declared as a function prototype.
To fix this issue we need to make sure both classes are declared before they are used. We separate the declaration from the definition. This MSDN article explains in more detail about the declarations and definitions.
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{ ... }
};
void A::CallFunction ()
{
B b;
b.bFunction();
}
What you should do, is put CallFunction into *.cpp file, where you include B.h.
After edit, files will look like:
B.h:
#pragma once //or other specific to compiler...
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
B.cpp
#include "B.h"
void A::CallFunction(){
//use B object here...
}
Referencing to your explanation, that you have tried to change B b; into pointer- it would be okay, if you wouldn't use it in that same place. You can use pointer of undefined class(but declared), because ALL pointers have fixed byte size(4), so compiler doesn't have problems with that. But it knows nothing about the object they are pointing to(simply: knows the size/boundary, not the content).
So as long as you are using the knowledge, that all pointers are same size, you can use them anywhere. But if you want to use the object, they are pointing to, the class of this object must be already defined and known by compiler.
And last clarification: objects may differ in size, unlike pointers. Pointer is a number/index, which indicates the place in RAM, where something is stored(for example index: 0xf6a7b1).
class B is only declared but not defined at the beginning, which is what the compiler complains about. The root cause is that in class A's Call Function, you are referencing instance b of type B, which is incomplete and undefined. You can modify source like this without introducing new file(just for sake of simplicity, not recommended in practice):
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
// postpone definition of CallFunction here
void A::CallFunction ()
{
B b;
b.bFunction();
}
in A you have used a definition of B which is not given until then , that's why the compiler is giving error .
Forward declare class B and swap order of A and B definitions: 1st B and 2nd A. You can not call methods of forward declared B class.
Here's my solution to the issue. Tried to keep it straight and simple.
#include <iostream>
using namespace std;
class Game{
public:
void init(){
cout << "Hi" << endl;
}
}g;
class b : Game{ //class b uses/imports class Game
public:
void h(){
init(); //Use function from class Game
}
}A;
int main()
{
A.h();
return 0;
}
You can also have a look at the curiously recurring template pattern and solve your problem similar to this:
template<typename B_TYPE>
struct A
{
int callFctn()
{
B_TYPE b;
return b.bFctn();
}
};
struct B : A<B>
{
int bFctn()
{
return 5;
}
};
int main()
{
A<B> a;
return a.callFctn();
}