I provide to you a MWE:
#include <iostream>
class C;
class A
{
public:
A(C &cc)
: c(cc)
{
}
int functionA()
{
return 0;
}
C &c;
};
class B
{
public:
B(C &cc)
: c(cc)
{
}
int functionB()
{
return c.a.functionA();
}
C &c;
};
class C
{
public:
C()
: a(*this)
, b(*this)
{
}
int functionC()
{
return b.functionB();
}
A a;
B b;
};
int main()
{
C c;
std::cout << c.functionC() << std::endl;
}
And associated compiler error:
main.cpp: In member function ‘int B::functionB()’:
main.cpp:37:16: error: invalid use of incomplete type ‘class C’
37 | return c.a.functionA();
| ^
main.cpp:5:7: note: forward declaration of ‘class C’
5 | class C;
| ^
Further explanation is probably not required, however, the class C is not fully defined by the time we reach line return c.a.functionA().
What is the most appropriate way to break this interdependence problem?
If it helps to guide, then consider the following context
C = Host
A = CPU
B = RAM
and the actual code where this problem occurs in my project is
void CPU::MemFetchByte(byte &ret, const addr_t addr)
{
HardwareDevice::host.memory.GetByte(ret, addr);
}
perhaps this is useful additional info, perhaps it is not.
Additionally, I tried to invert the problem as follows
#include <iostream>
//class C;
class A;
class B;
class C
{
public:
C()
: a(new A(*this))
, b(new B(*this))
{
}
~C()
{
delete b;
delete a;
}
int functionC()
{
return b->functionB();
}
A *a;
B *b;
};
class A
{
public:
A(C &cc)
: c(cc)
{
}
int functionA()
{
return 0;
}
C &c;
};
class B
{
public:
B(C &cc)
: c(cc)
{
}
int functionB()
{
return c.a->functionA();
}
C &c;
};
int main()
{
C c;
std::cout << c.functionC() << std::endl;
}
however this (as expected) makes things worse not better:
main.cpp:16:24: error: invalid use of incomplete type ‘class A’
16 | : a(new A(*this))
| ^
main.cpp:6:7: note: forward declaration of ‘class A’
6 | class A;
| ^
main.cpp:17:24: error: invalid use of incomplete type ‘class B’
17 | , b(new B(*this))
| ^
main.cpp:7:7: note: forward declaration of ‘class B’
7 | class B;
| ^
Work with complete types by moving the constructors and member function implementations out of the class declarations.
#include <iostream>
class A;
class B;
class C;
class A {
public:
A(C &cc);
int functionA();
C &c;
};
class B {
public:
B(C &cc);
int functionB();
C &c;
};
class C {
public:
C();
int functionC();
A a;
B b;
};
int main()
{
C c;
std::cout << c.functionC() << std::endl;
}
A::A(C &cc) : c(cc)
{ }
int A::functionA() {
return 0;
}
B::B(C &cc) : c(cc)
{ }
int B::functionB() {
return c.a.functionA();
}
C::C() : a(*this), b(*this)
{ }
int C::functionC() {
return b.functionB();
}
int functionB()
{
return c.a.functionA();
}
This function needs to be defined outside of the class body, after class C is defined.
You can apply the same idea to your second attempt (the definitions for C(), ~C(), and functionC() will need to be moved). But this is worse than your first attempt, because you're using heap allocation for no good reason (and class C doesn't follow the rule of three).
It looks like classes A and B are parts of system C, so that another option is to compose C from A and B using derivation. This allows A and B to get to C with a simple downcast, no C& c member is required:
struct C;
struct A {
void fa();
};
struct B {
void fb();
};
struct C : A, B {
void fc();
};
void A::fa() {
static_cast<C&>(*this).fc();
}
void B::fb() {
static_cast<C&>(*this).fc();
}
Related
say I have this program situation overhere:
struct A
{
int(*func_ptr)();
};
struct B
{
int b = 0;
void SetFunctionPointerToLambda(A& a)
{
a.func_ptr = [=] () { return b; };
}
};
int main()
{
A a;
B b;
b.SetFunctionPointerToLambda(a);
}
I want to set a function pointer of an object A to a lambda, which is based of the values of an object B.
So, how is this going to be done?
Current error message:
loeschen5.cc: In member function 'void B::SetFunctionPointerToLambda(A&)':
loeschen5.cc:14:41: error: cannot convert 'B::SetFunctionPointerToLambda(A&)::<lambda()>' to 'int (*)()' in assignment
a.func_ptr = [=] () { return b; };
^
Thanks for any help!
Ok, so I solved this with a functional object:
So, not only the function, but also the necessary variables are stored:
struct FunctionObject
{
const int *b;
int operator ()() const
{
return *b;
}
};
struct A
{
FunctionObject func_ptr;
};
struct B
{
int b = 56;
void SetFunctionPointerToLambda(A& a) const
{
a.func_ptr = FunctionObject { &b };
}
};
int main()
{
A a;
B b;
b.SetFunctionPointerToLambda(a);
}
And it works fine.
error: passing 'const A' as 'this' argument of 'void A::hi()' discards
qualifiers [-fpermissive]
I don't understand why I'm getting this error, I'm not returning anything just passing the reference of the object and that is it.
#include <iostream>
class A
{
public:
void hi()
{
std::cout << "hi." << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.hi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
#edit
I fixed it using const correctness but now I'm trying to call methods inside of the same method and I get the same error, but the weird thing is that I'm not passing the reference to this method.
#include <iostream>
class A
{
public:
void sayhi() const
{
hello();
world();
}
void hello()
{
std::cout << "world" << std::endl;
}
void world()
{
std::cout << "world" << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.sayhi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
error: passing 'const A' as 'this' argument of 'void A::hello()'
discards qualifiers [-fpermissive]
error: passing 'const A' as 'this' argument of 'void A::world()'
discards qualifiers [-fpermissive]
Your hi method is not declared as const inside your A class. Hence, the compiler cannot guarantee that calling a.hi() will not change your constant reference to a, thus it raises an error.
You can read more about constant member functions here and correct usage of the const keyword here.
// **const object can call only const member function()**
// **Modified Code**
#include <bits/stdc++.h>
using namespace std;
class A {
public:
void hi() const {
std::cout << "hi." << std::endl;
}
};
class B {
public:
void receive(const A& a) {
a.hi();
}
};
class C {
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
A a;
C c;
c.receive(a);
return 0;
}
As already mentioned, one option is to make hi method const-qualified.
Another option is to use const_cast at the time of calling the hi method like so
A& ref = const_cast <A&>(a);
ref.hi();
Looking for how to best access class B's queue through A but I am receiving a segmentation fault. Also I am looking for the best way to communicate between these two classes. Are accessor methods ok in this scenario? What design pattern could work? Thanks
class B {
public:
int get_int() { return qi.front(); }
void put_int(int i) { qi.push(i); }
private:
queue<int> qi;
};
class A
{
public:
void get_event() { cout << b->get_int() << endl; }
void put_event(int a) { b->put_int(a); }
private:
B *b;
};
int main() {
A a;
a.put_event(1);
return 0;
}
As mentioned in comment problem is undefined initialization
you can fix that by using constructor for initialization
#include<iostream>
#include<queue>
using namespace std;
class B {
public:
int get_int() { return qi.front(); }
void put_int(int i)
{
qi.push(i);
}
private:
queue<int> qi;
};
class A
{
public:
void get_event() { cout << b->get_int() << endl; }
void put_event(int a) { b->put_int(a); }
A()
{
b = new B();
}
~A() { delete b; }
private:
B *b;
};
int main() {
A a;
a.put_event(1);
a.get_event();
return 0;
}
Output
1
Program ended with exit code: 0
A a;
is an undefined reference, you have to initialize it with a costructor and since you didn't defined any, you must use the default one
A a=new A();
or better, write the costructors of the two classes as you prefer and use them.
I'll describe my question using the following sample code.
I have class B defined as follows:
class B
{
public:
inline B(){}
inline B(int(*f)(int)) :myfunc{ f }{}
void setfunction(int (*f)(int x)) { myfunc = f; }
void print(int number) { std::cout << myfunc(number) << std::endl; }
private:
int(*myfunc)(int);
};
I then define class A as follows:
class A
{
public:
A(int myint) :a{ myint }{ b.setfunction(g); }
int g(int) { return a; }
void print() { b.print(a); }
private:
B b;
int a;
};
To me the issue seems to be that the member function g has the signature int A::g(int) rather than int g(int).
Is there a standard way to make the above work? I guess this is quite a general setup, in that we have a class (class B) that contains some sort of member functions that perform some operations, and we have a class (class A) that needs to use a particular member function of class B -- so is it that my design is wrong, and if so whats the best way to express this idea?
You can use std::function:
class B
{
public:
inline B() {}
inline B(std::function<int(int)> f) : myfunc{ f } {}
void setfunction(std::function<int(int)> f) { myfunc = f; }
void print(int number) { std::cout << myfunc(number) << std::endl; }
private:
std::function<int(int)> myfunc;
};
class A
{
public:
A(int myint) :a{ myint } {
b.setfunction([this](int a) {
return g(a);
}
);
}
int g(int) { return a; }
void print() { b.print(a); }
private:
B b;
int a;
};
You could generalize the class B. Instead of keeping a pointer (int(*)(int)), what you really want is any thing that I can call with an int and get back another int. C++11 introduced a type-erased function objection for exactly this reason: std::function<int(int)>:
class B
{
using F = std::function<int(int)>
public:
B(){}
B(F f) : myfunc(std::move(f)) { }
void setfunction(F f) { myfunc = std::move(f); }
void print(int number) { std::cout << myfunc(number) << std::endl; }
private:
F myfunc;
};
And then you can just provide a general callable into B from A:
A(int myint)
: b([this](int a){ return g(a); })
, a{ myint }
{ }
Use std::function and std::bind
class B
{
public:
inline B(int(*f)(int)) :myfunc{ f }{}
void setfunction(std::function<int(int)> f) { myfunc = f; }
void print(int number) { std::cout << myfunc(number) << std::endl; }
private:
std::function<int(int)> myfunc;
};
// ...
A a;
B b(std::bind(&A::g, &a));
Also note that you should initialize the function pointer to some default value (most likely null) and check for it when using, otherwise it's value is undefined.
You could use std::bind to bind the member function A::g.
class B
{
public:
inline B(){}
inline B(std::function<int(int)> f) :myfunc{ f }{}
void setfunction(std::function<int(int)> f) { myfunc = f; }
void print(int number) { std::cout << myfunc(number) << std::endl; }
private:
std::function<int(int)> myfunc;
};
class A
{
public:
A(int myint) :a{ myint } {
b.setfunction(std::bind(&A::g, this, std::placeholders::_1));
}
int g(int) { return a; }
void print() { b.print(a); }
private:
B b;
int a;
};
Note you need to change the type of functor from function pointer to std::function, which is applicable with std::bind.
LIVE
I have found the following example in one of my C++ courses. When I try to compile it I get the following error:
'B::operator A' uses undefined class 'A'
Why does it say that class A is undefined?
#include<iostream>
using namespace std;
class A;
class B
{
int x;
public: B(int i = 107) { x = i; }
operator A();
};
B::operator A() { return x; }
class A
{
int x;
public: A(int i = 6) { x = i; }
int get_x() { return x; }
};
int main()
{
B b;
A a = b;
cout << a.get_x();
system("Pause");
}
The compiler needs to know what A is here:
B::operator A() { return x; }
But you only have a forward declaration. You need to move the declaration of class A above B
You are only allowed to use pointers to or references of incomplete types which is what have when you forward declare a type
You need to declare A above B, so that the definition of A is visible to B.
#include<iostream>
using namespace std;
class A
{
int x;
public: A(int i = 6) { x = i; }
int get_x() { return x; }
};
class B
{
int x;
public: B(int i = 107) { x = i; }
operator A();
};
B::operator A() { return x; }
int main()
{
B b;
A a = b;
cout << a.get_x();
}
This should work.