Is it possible in C++ to split the definition of class members in two headers? What would be the appropriate way to code it?
For instance:
a1.h
class A {
public:
int var;
void foo1(int b);
}
a1.cpp
#include "a1.h"
void A::foo1(int b) {
cout << b;
}
a2.h
[extend] class A {
public:
void foo2(double c);
}
a2.cpp
#include "a2.h"
void A::foo2(double c) {
cout << c;
}
You can't extend a class that way, but you can use the pimpl pattern:
class A {
public:
void foo1(int b);
private:
AImpl* pimpl;
}
and then have AImpl.h and AImpl.cpp that hides all the private details.
Related
I'm trying to generate header files of classes I'm reconstructing from what I disassembled with IDA. However I'm getting compile errors due to circular dependencies. For regular classes I solved it by declaring them in a separate file I include as a first. The thing is I cannot declare inner class without definition of an outer class which is the problem.
An example class structure:
Class A:
#include "B.h"
class A {
public:
class Nested {
public:
void foo(B::Nested &foo);
};
};
Class B:
#include "A.h"
class B {
public:
class Nested {
public:
void foo(A::Nested &foo);
};
};
You can forward declare the Nesteds in A and B, and define them afterward.
a.h
class A {
public:
class Nested;
};
B.h
class B {
public:
class Nested;
};
Nested.h
#include "A.h"
#include "B.h"
class A::Nested {
public:
void foo(B::Nested &foo);
};
class B::Nested {
public:
void foo(A::Nested &foo);
};
Use templates.
class A {
public:
class Nested {
public:
template<class B>
void foo(typename B::Nested &fo);
};
};
class B {
public:
class Nested {
public:
template<class A>
void foo(typename A::Nested &fo);
};
};
template<>
void A::Nested::foo<B>(B::Nested &fo){
}
template<>
void B::Nested::foo<A>(A::Nested &fo){
}
e.g. (Here the template has been moved up so the type doesn't have to be specified with each function call.)
#include <iostream>
class A {
public:
template <class B>
class Nested {
public:
std::string name() const { return "a"; }
void foo(typename B:: template Nested<A> &fo);
};
};
class B {
public:
template <class A>
class Nested {
public:
std::string name() const { return "b"; }
void foo(typename A:: template Nested<B> &fo);
};
};
template<>
void A::Nested<B>::foo(B::Nested<A> &fo){
std::cout << "A::Nested " << fo.name() << '\n';
}
template<>
void B::Nested<A>::foo(A::Nested<B> &fo){
std::cout << "B::Nested " << fo.name() << '\n';
}
int main()
{
A::Nested<B> a;
B::Nested<A> b;
a.foo(b);
b.foo(a);
}
When a compiler reads your file it is expecting declared entities.
You can forward declare the class but you would be missing the Nested Parameter type.
What you can do is to have a third class which breaks the circular dependency and inherits to the your nested classes:
class NestedBase {
};
Now use this base in your A nested class:
#include "NestedBase.h"
class A {
public:
class Nested : public NestedBase {
public:
void foo(NestedBase &foo);
};
};
And in your B nested class as well:
#include "NestedBase.h"
class B {
public:
class Nested : public NestedBase {
public:
void foo(NestedBase &foo);
};
};
Now with dynamic_cast in your method implementations you can convert them to your desired types and access whatever you declared in your Nested Classes.
#include "A.h"
#include "B.h"
B::Nested::foo(NestedBase &foo)
{
auto &fooA = dynamic_cast<A::Nested&>(foo);
...
}
I have a class A with the following declaration (A.h file):
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#endif
and a class B deriving from that class (B.h file):
#ifndef __B_DEFINED__
#define __B_DEFINED__
#include <iostream>
#include "A.h"
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
So far, so good. My issue is that the function A::doThat() uses B::doThis():
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
Usually, the circular dependency would not be an issue because I would just define A::doThat() in the .cpp file. In my case however, doThat is a template function so I can't do that.
Here are the solutions I have envisioned so far:
Defining the template function A::doThat() in a .cpp file. The issue with that is that I need to instantiate explicitly all the calls with various template arguments (there might be many in the real case).
After the declaration of the A class in A.h, add #include "B.h" and then define the A::doThat() function. This works fine in visual studio but g++ does not like it.
Is there a neat way to solve this problem?
EDIT: In the real case, there is not just one child class B, but several (B, C, D, etc.) The function A::doThat() depends on all of them. The function B::doThis() is also templated.
A default template parameter for the B class could work:
#include <iostream>
// include A.h
class B;
class A
{
public:
template<typename T, typename U = B> inline void doThat() const
{
U b; b.doThis();
}
};
// include B.h
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
// main
int main()
{
A a;
a.doThat<int>();
}
Usually the best way to allow a parent to call a child function is to declare the function as a pure virtual function in the parent and override it in the children.
#include <iostream>
class A
{
public:
virtual ~A() = default;
template<typename T> inline void doThat() const
{
// do some other stuff
doThis();
}
virtual void doThis() const = 0; // pure virtual function
};
class B: public A
{
public:
void doThis() const override
{
std::cout << "do this!" << std::endl;
}
};
int main()
{
B b;
A* ap = &b;
ap->doThat<int>();
}
The following does work with g++:
File A.h:
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#include "B.h"
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
#endif
File B.h:
#include <iostream>
#include "A.h"
// We check for the include guard and set it AFTER the inclusion of A.h
// to make sure that B.h is completely included from A.h again.
// Otherwise the definition of A::doThat() would cause a compiler error
// when a program includes B.h without having included A.h before.
#ifndef __B_DEFINED__
#define __B_DEFINED__
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
File test_A.cpp:
// In this test case we directly include and use only A.
#include "A.h"
#include "A.h" // We test whether multiple inclusion causes trouble.
int main() {
A a;
a.doThat<int>();
}
File test_B.cpp:
// In this test case we directly include and use only B.
#include "B.h"
#include "B.h" // We test whether multiple inclusion causes trouble.
int main() {
B b;
b.doThat<int>();
b.doThis();
}
Alternative Idea:
I do not know whether you (or some coding conventions) insist on separate header files for each class, but if not the following should work:
You can put the definitions of class A and class B and of the member function template A::doThat<typename>() (in this order) together in one header file AandB.h (or whatever name you like).
This cries for polymorphism. There are two options using polymorphism:
Dynamic polymorphism, i.e. make A an abstract base class and call doThis() virtually:
struct A
{
virtual void do_this() const = 0;
template<typename T>
void doThat() const { doThis(); }
};
struct B : A
{
void doThis() const override { /* ... */ }
};
Of course, this only works if doThis() is not templated. If you need that, you could use
Static polymorphism, i.e. CRTP, when
template<typename Derived>
struct A
{
template<typename T>
void doThat() const { static_cast<const Derived*>(this)->template doThis<T>(); }
};
struct B : A<B>
{
template<typename T>
void doThis() const { /* ... */ }
};
If (as in your example code) B::doThis() is not called for the same object, but for some temporary, you could
template<typename typeB>
struct A
{
template<typename T>
void doThat() const { typeB b; b.template doThis<T>(); }
};
In Objective C the language has built in support for delegation of classes to other classes. C++ does not have such feature (one class as a delegate of another class) as part of the language. A way to mimic that is to separate declaration and implementation this way:
In header file a.h:
class AImpl;
class A
{
public:
A();
void f1();
int f2(int a, int b);
// A's other methods...
private:
AImpl *mImpl;
};
In the .cpp (implementation file):
#include "a.h"
class AImpl
{
public:
AImpl();
// repeating the same method declarations from A
void f1();
int f2(int a, int b);
// AImpl's other methods
};
AImpl::AImpl()
{
}
void AImpl:f1()
{
// actual implemetation
}
int AImpl::f2(int a, int b)
{
// actual implmentation
}
// AImpl's other methods implementation
A::A()
{
mImpl = new AImpl();
}
// A's "forwarder"
void A::f1()
{
mImpl->f1();
}
int A::f2(int a, int b)
{
return mImpl->f2(a, b);
}
// etc.
This requires manually creating all "forwarder" functions in the class that would delegate to another class to do the actual work. Tedious, to say the least.
The question is: is there a better or more productive way to achieve this effect using templates or other C++ langage constructs?
Yes it's possible. One of possible examples is:
struct WidgetDelegate
{
virtual ~WidgetDelegate() {}
virtual void onNameChange(std::string newname, std::string oldname) {}
};
class Widget
{
public:
std::shared_ptr<WidgetDelegate> delegate;
explicit Widget(std::string name) : m_name(name){}
void setName(std::string name) {
if (delegate) delegate->onNameChange(name, m_name);
m_name = name;
}
private:
std::string m_name;
};
Usage:
class MyWidgetDelegate : public WidgetDelegate
{
public:
virtual void onNameChange(std::string newname, std::string oldname) {
std::cout << "Widget old name: " << oldname << " and new name: " << newname << std::endl;
}
};
int main()
{
Widget my_widget("Button");
my_widget.delegate = std::make_shared<MyWidgetDelegate>();
my_widget.setName("DoSomeThing");
return 0;
}
Required includes are:
#include <string>
#include <iostream>
#include <memory>
You can implement a virtual interface in the base class.
However, if you really want to delegate, then you can overload the operator-> to delegate all calls.
You won't need anymore the forwarding methods:
#include <iostream>
#include <string>
using namespace std;
class AImpl;
class A
{
public:
A();
//Overloading operator -> delegates the calls to AImpl class
AImpl* operator->() const { return mImpl; }
private:
AImpl *mImpl;
};
class AImpl
{
public:
void f1() { std::cout << "Called f1()\n"; }
void f2() { std::cout << "Called f2()\n"; }
};
A::A()
{
mImpl = new AImpl();
}
int main()
{
A a;
a->f1(); //use a as if its a pointer, and call functions of A
A* a1 = new A();
(*a1)->f2();
}
I have a class A which is in a separate file(sayfile1.cpp)
class A{
public:
virtual int add(){
int a=5;
int b=4;
int c = a+b;
return c;
}
};
Now in a different file(say file2.cpp), i have a function(i have a many other things in this function) inside which i want to create a class inherited from class A and implement the virtual method declared in class A.
void function(Mat param1, Mat param2)
{
//Some process here..
..
..
int c=100;
class B:public A{
public:
virtual int add(){
return c;
}
};
}
Now if i were to call the function int add(), i want the result of c to be 100 and not 9.
Is it possible to do something like this in C++ ??
Thanks in advance
Define member variable:
class B: public A {
int c_;
public:
explicit B(int c):c_(c){};
virtual int add() {
return c_;
}
}
B variable((100));
You need to split your file1.cpp into file1.h:
#ifndef FILE1_H
class A {
public:
virtual int add();
};
#endif
and file1.cpp with it's implementation:
int A::add { /*your code * }
In the other file you include only the header file:
#include "file1.h"
The following is not legal in C++:
void function(Mat param1, Mat param2)
{
//Some process here..
..
..
int c=100;
class B:public A {
public:
virtual int add(){
return c;
}
};
}
Instead, you need something like this:
class B : public A {
public:
B(int v) : c(v) {}
virtual int add(){ return c; }
private:
int c;
};
void function(Mat param1, Mat param2)
{
//Some process here..
..
..
int c=100;
B o(c);
}
Please see the example code below:
class A
{
private:
class B
{
public:
foobar();
};
public:
foo();
bar();
};
Within class A & B implementation:
A::foo()
{
//do something
}
A::bar()
{
//some code
foo();
//more code
}
A::B::foobar()
{
//some code
foo(); //<<compiler doesn't like this
}
The compiler flags the call to foo() within the method foobar(). Earlier, I had foo() as private member function of class A but changed to public assuming that B's function can't see it. Of course, it didn't help. I am trying to re-use the functionality provided by A's method. Why doesn't the compiler allow this function call? As I see it, they are part of same enclosing class (A). I thought the accessibility issue for nested class meebers for enclosing class in C++ standards was resolved.
How can I achieve what I am trying to do without re-writing the same method (foo()) for B, which keeping B nested within A?
I am using VC++ compiler ver-9 (Visual Studio 2008). Thank you for your help.
foo() is a non-static member function of A and you are trying to call it without an instance.
The nested class B is a seperate class that only has some access privileges and doesn't have any special knowledge about existing instances of A.
If B needs access to an A you have to give it a reference to it, e.g.:
class A {
class B {
A& parent_;
public:
B(A& parent) : parent_(parent) {}
void foobar() { parent_.foo(); }
};
B b_;
public:
A() : b_(*this) {}
};
This is an automagic, albeit possibly nonportable trick (worked on VC++ since 6.0 though). Class B has to be a member of class A for this to work.
#ifndef OUTERCLASS
#define OUTERCLASS(className, memberName) \
reinterpret_cast<className*>(reinterpret_cast<unsigned char*>(this) - offsetof(className, memberName))
#endif
class A
{
private:
class B
{
public:
void foobar() {
A* pA = OUTERCLASS(A, m_classB);
pA->foo();
}
} m_classB;
public:
foo();
bar();
};
Basically what Georg Fritzsche said
#include <iostream>
#include <cstring>
using namespace std;
class A
{
private:
class B
{
A& parent_;
public:
//B(); //uncommenting gives error
~B();
B(A& parent) : parent_(parent) {}
void foobar()
{
parent_.foo();
cout << "A::B::foo()" <<endl;
}
const std::string& foobarstring(const std::string& test) const
{
parent_.foostring(test); cout << "A::B::foostring()" <<endl;
}
};
public:
void foo();
void bar();
const std::string& foostring(const std::string& test) const;
A();
~A(){};
B b_;
};
//A::B::B() {}; //uncommenting gives error
A::B::~B(){};
A::A():b_(*this) {}
void A::foo()
{
cout << "A::foo()" <<endl;
}
const std::string& A::foostring(const std::string& test) const
{
cout << test <<endl;
return test;
}
void A::bar()
{
//some code
cout << "A::bar()" <<endl;
foo();
//more code
}
int main(int argc, char* argv[])
{
A a;
a.b_.foobar();
a.b_.foobarstring("hello");
return 0;
}
If you uncomment the default B constructor you would get an error
If you want to reuse functionality from A then you should inherit from A not nest B inside it.
Combining Igor Zevaka's and enthusiasticgeek's answers. Also, using reinterpret_cast for calculating offset (If you create class member variable using new keyword):
#include <iostream>
#include <cstring>
using namespace std;
template < typename T, typename U > constexpr size_t offsetOf(U T:: *member)
{
return (char*) &((T*) nullptr->*member) - (char*) nullptr;
}
class A
{
private:
class B
{
public:
B(string message);
~B();
void foobar()
{
A *pA = reinterpret_cast<A*> (reinterpret_cast< unsigned char*> (this) - offsetOf(&A::b_));
pA->foo();
pA->bar();
std::cout << "DONE!";
}
};
public:
void foo();
void bar();
A();
~A() {};
B* b_ = new B("Hello World!");
};
A::A()
{
cout << "A constructor\n";
};
A::B::B(string message) {
cout << "B constructor\n";
cout << "Message = " << message << "\n";
};
A::B::~B() {};
void A::foo()
{
cout << "A::foo()" << endl;
}
void A::bar()
{
cout << "A::bar()" << endl;
foo();
}
int main(int argc, char *argv[])
{
A* a = new A();
a->b_->foobar();
return 0;
}
Output:
B constructor
Message = Hello World!
A constructor
A::foo()
A::bar()
A::foo()
DONE!
References:
https://stackoverflow.com/a/10607424/9524565
https://stackoverflow.com/a/3058382/9524565
https://stackoverflow.com/a/20141143/9524565