I'm sure this question has already been asked in one form or another, but I couldn't find the clue. Please consider the following C++-code:
// A.h
class A
{
public:
A();
virtual ~A();
virtual void setVisibility(bool v);
virtual bool setVisibility();
protected:
bool visibility;
};
// B.h
class B : public A
{
public:
B();
virtual ~B();
};
// C.h
class C : public B
{
public:
C();
virtual ~C();
virtual void setVisibility(bool v);
virtual bool setVisibility();
};
// A.cpp
#include "common.h"
A::A() {}
A::~A() {}
void A::setVisibility(bool v) { this->visibility = v; }
bool A::setVisibility() { return this->visibility; }
// B.cpp
#include "common.h"
B::B() {}
B::~B() {}
// C.cpp
#include "common.h"
C::C() {}
C::~C() {}
void C::setVisibility(bool v) { /* do nothing */ }
bool C::setVisibility() { return false; }
// common.h - does nothing else than joining the header files together
#include "A.h"
#include "B.h"
#include "C.h"
calling:
C* myC = new C();
cout << "Set visibility true" << endl;
myC->setVisibility(true);
I tried several things. If I declare both methods virtually in C, it compiles but I get a segmentation fault at myC->setVisibility(true). If I remove the declaration (which shouldn't be necessary anyway, as they're inherited from B and A, right?), then it tells me that C doesn't have these methods.
And I don't want to reimplement the methods in B. If I declare them everywhere including B, it tells me that there's no implementation of these methods in B.
What should I do now? I need virtual, because I'm not always gonna use C as variable type in the calling example.
I'm using GCC on a 64 bit machine.
Edit: Corrected the copy/paste-mistake. I named the classes A, B and C for simplicity and didn't copy the code correctly. But unfortunately, the problem remainsEdit 2: Added common.hEdit 3: Hmm... copying this code actually works fluently. But the architecture is the same. Except that I compile my code into a shared library using the flags -shared -fPIC. The calling code is in the application that uses this library. Nothing else is different. Gotta check again.
Thanks for any tips pointing me to the right direction. regards
in C.cpp, don't define A::setVisibility(), it should be C::setVisibility()
In C.cpp, you're defining A::setVisibility, not C::setVisibility.
You can change your class C to:
// C.h
class C : public B
{
public:
C();
virtual ~C();
using A::setVisibility;
virtual bool setVisibility();
};
This will "reintroduce" all kinds of setVisibility defined in A.
The other answers are all correct before the correction. But it's not the solution to the problem. There actually isn't any problem at all. The problem lies in my implementation of the setVisibility-method, that's where the segfault occurs. Therefore the solution can't be found here.
Thanks to all who tried to help!
regards
Related
a.h
#ifndef _A__
#define _A__
class A {
public:
struct Less {
bool operator() (const A* const &k1, const A* const &k2) const
{
return k1->_a < k2->_a;
}
};
A(int a) : _a(a)
{
;
}
virtual ~A()
{
;
}
private:
int _a;
};
#endif
b.h
#ifndef _B__
#define _B__
#include "a.h"
class B : public A {
public:
B(int a) : A(a)
{
;
}
~B()
{
;
}
};
#endif // _B__
c.cpp
#include <set>
#include "a.h"
class B;
class C
{
std::set<B*, A::Less> _set;
};
When c.cpp is compile with g++ 8.1, it fails to compile with this static check error
/export/dev6/rajpal/gcc/8.1.0/bin/g++ -c c.cpp
In file included from /export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/set:60,
from c.cpp:1:
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h: In instantiation of 'class std::_Rb_tree<B*, B*, std::_Identity<B*>, A::Less, std::allocator<B*> >':
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_set.h:133:17: required from 'class std::set<B*, A::Less>'
c.cpp:6:25: required from here
/export/dev6/rajpal/gcc/8.1.0/include/c++/8.1.0/bits/stl_tree.h:452:21: error: static assertion failed: comparison object must be invocable with two arguments of key type
static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I understand error is because at compile time, compiler is not able to determine how to compare _Key=B* and if I make available definition of B, it should work just fine.
But, my question is if there is any way to tell compiler that B is actually derived from A and there is a way to compare A objects.
Also please note that I don't want to change std::set<B*, A::Less> to std::set<A*, A::Less> which should also fix this problem.
Well, this is actually a libstdc++ bug, and will be fixed in GCC 8.4:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85965
But, my question is if there is any way to tell compiler that B is actually derived from A
The only way to do that is to make the definition of B visible where you need that information.
There is nothing like forward declaration of classes to indicate that B is derived from A.
I want to call a class which is only in the file of a parent source class file. In fact I have 3 classes in 4 files:
parent.h
parent.cpp
child.h
child.cpp
The "main" classes are Child and Parent. The class Otherclass is in the parent.h file above the definition of the Parent class.
How can I get access to the class Otherclass which is only in the parent.cpp file in the child.cpp file?
(Unfortunately I'm not allowed to make big changes in the parent files.)
parent.cpp:
using ParentNamespace::Parent;
namespace other
{
class Otherclass
{
public:
Otherclass()
{
// do something
}
~Otherclass()
{
}
};
}
Parent::Parent()...
...
// here the Parent class continues normal
child.cpp:
#include "parent.h"
Child::Child() :
ParentNamespace::Parent()
...
...
...
// here I want to use Otherclass
How can I get acess to the class 'Otherclass' which is only in the parent.cpp file in the child.cpp file?
You can't. This is the entire purpose of header files. Use them.
(Unfortunately i'm not allowed to make big changes in the parent files.)
Either the existing code is completely broken and you should use this fact to become allowed…
…or these are internal classes that you shouldn't be trying to use in this way.
You can always create a separate header file for OtherClass, copy the OtherClass definition (all the code you would usually out into the header, not the code of non-inlined functions) there and #include this header into child.h. It is not very bad to have several definitions of the same class as long as you are absolutely sure that they will be identical. It is not also a right way to do, but if you can not move the OtherClass definition to (some) header file, then you can copy it to a new header.
Although of course the first question to ask is why at all the existing code is done this way. Maybe OtherClass is just an implementation detail of Parent that may change in future development and which you are not supposed to use.
An example code (not exactly for your case, but illustrates how you can work without any header files at all):
// a.cpp
#include <iostream>
class A{
public:
int x;
A(int);
};
class B {
public:
int y;
B(int);
};
A::A(int v) {
std::cout << "A::A " << v << std::endl;
}
// b.cpp
#include <iostream>
class A{
public:
int x;
A(int);
};
class B {
public:
int y;
B(int);
};
B::B(int v) {
std::cout << "B::B " << v << std::endl;
A a(v+10);
}
// main.cpp
class A{
public:
int x;
A(int);
};
class B {
public:
int y;
B(int);
};
int main() {
A a(10);
B b(20);
}
builds and works as expected. However, it would be really difficult to maintain all the definitions identical, so that's what headers are for.
I have these files (simplified version)
a.h
class A
{
public:
A(int){}
int operator [](int a){return a;}
};
A a(2);
main.cpp
#include<a.h>
class B
{
public:
B(int){}
};
B b(a[2]);
int main()
{
//use b here...
}
Q: Can I use the above code ? Is it correct ?!
The code above (almost) compiles, but it probably doesn't do what you'd expect. A couple issues . . .
#include<a.h> should probably be #include "a.h" if a.h is located in the same directory as main.cpp.
B b(a[2]) might create a new instance of class A, instead of using the one you defined in a.h. Add extern A a; before you use a to tell your compiler that you want to use the a declared in another file.
Finally, depending on your application sometimes global variables can be frowned upon. If it's appropriate, consider using encapsulation instead of global variables. Something like
Class B {
public:
B(int i){}
private:
A a(); // Or extern A a;
};
Would work if you only needed to access a from b.
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();
}
I have a base interface class:
class A
{
public:
ITask(){}
virtual bool Start()=0;
virtual void Update()=0;
virtual void Stop()=0;
};
I now have 2 other classes, that inherit from this
#include "A.h"
#include "C.h"
class B: public A
{
public:
bool Start(){}
void Update()
{
c.Start();
}
void Stop(){}
static bool m_run;
static void SetRun(bool run)
{
m_run = run;
}
private:
C c;
};
lastly I have a 3rd class:
#include "A.h"
#include "B.h"
class C : public A
{
public:
bool Start()
{
B::SetRun(false); // cant do this
B::m_run = false; // or this
}
void Update()
{
}
void Stop()
{
}
}
I have shaved down some of the code, for simplicity.
I dont understand why I cant access the static var in B. Do I need to make it a pointer or a ref?
I get 2 errors:
error C2653: 'B' : is not a class or namespace name
error C3861: 'm_run': identifier not found
Although you don't show it, I'm assuming that B.h includes C.h; otherwise the line C c; won't compile. This causes a circular dependency in the header files: B.h must be included before C.h, which must be included before B.h, which is impossible.
The easiest solution is to move the body of C::Start out of the definition of C, so that C.h does not need to include B.h. The function definition can go into a source file, or a separate header if you want to keep it inline.
Alternatively, you could modify B to contain a std::unique_ptr<C> rather than an instance of C, and implement a constructor (in a source file, or a separate header) that initialises it with new C. Then B.h only needs to forward declare class C; rather than including C.h.
A better solution, if possible, would be to rethink the relationships between the classes so that there isn't a circular dependency.
(UPDATE: while I was writing this answer, the question changed to show that B.h does indeed include C.h as I guessed.)
There is nothing wrong with your example code (after the edits), the problem must be somewhere else, like a failed include.