Forward declaring a C++ class in Objective-C - c++

I am writing an Objective-C class that needs to make function calls on a C++ class instance. I found this suggestion, but if I try it I get an error for having an incomplete definition of type 'struct MyCPlusPlusClass'
struct MyCPlusPlusClass;
typedef struct MyCPlusPlusClass MyCPlusPlusClass;
#interface MyBridgeClass() {
MyCPlusPlusClass *my_CPlusPlus;
}
...
- (id)initWithMrGame:(MyCPlusPlusClass *)cPlusPlus
{
self = [super init];
if (self) {
my_CPlusPlus = cPlusPlusClass;
my_CPlusPlus->p_favorite_integer = 0; // Compiler error
}
return self;
}
The actual definition occurs in a .mm file that's generated by a pre-compiler, just to add another layer of challenge.
How might I get this to work?
EDIT: Interpreting Adam's answer
// in MyCode.h
struct MyCPlusPlusClass; // Forward declaration, no need for #include/#import
#interface MyBridgeClass() {
struct MyCPlusPlusClass *my_CPlusPlus;
}
// in MyCode.m
#include MyCode.h
// in BigGenerateFile.mm
class MyCPlusPlusClass;
class MyCPlusPlusClass { ... }
My goal is to be able to use MyCPlusPlusClass in MyCode.m, but I can't include the .mm file because the compiler gets very unhappy. It may be that the way this thing is architected is going to make me go a different route.

You can't access member variables of incomplete structures/classes. To do so, you need to the full definition. Typically you use forward declarations in header files so that anything that includes that header doesn't pull in lots of unnecessary other header files it won't need, but for source files you usually need the full definitions.
So I'd suggest changing you code to something like this:
// Header file (.h)
struct MyCPlusPlusClass; // Forward declaration, no need for #include/#import
#interface MyBridgeClass() {
struct MyCPlusPlusClass *my_CPlusPlus;
}
// Source file (.mm)
#include "MyCPlusPlusClass.h"
...
// Can now access my_CPlusPlus->p_favorite_integer etc.

You can do a number of things on an incomplete type, but accessing members of an object of that type is not one of them.
A simple possible solution would be a helper function that's defined somewhere where the complete type is available:
void set_p_favorite_integer(MyCPlusPlusClass*, int);
// ...
set_p_favorite_integer(my_CPlusPlus, 0);

Related

pre-defining classes not working when using pointers to classes

I am trying to implement a listener. Because of many cross-references I am trying to avoid including other classes and pre-define them
My listener looks as follows
.h
class Book
{
public:
Book();
private:
std::vector<MyListener *> listeners_;
void Notify();
}
.cpp
Book::Book() {}
void Book::Notify() {
MyListener *p_listener;
for ( int i = 0; i < this->listeners_.size(); i++ ) {
p_listener = listeners_[i];
p_listener->Update(); // ERRORS THROWN HERE WHEN NOT INCLUDING LISTENER.H
}
}
This all works fine when I include the listener.h file
#include "listener.h"
But when I instead pre-declare Listener it doesnt work
class Listener;
It gives me the two errors
C:\CPP\qtTradeSim\qtTradeSim\test\book.cpp:33: error: C2027: use of undefined type 'Listener'
C:\CPP\qtTradeSim\qtTradeSim\test\book.cpp:33: error: C2227: left of '->Update' must point to class/struct/union/generic type
Is there a way to avoid including the Listener header?
In the header file of class Book, you should indeed use a forward declaration of MyListener, as the header only defines an std::vector of pointers to MyListener and does not need to know the full declaration of MyListener.
The implementation file of class Book, however, actually needs the full declaration of MyListener, as it calls its update method, so you would include listener.h in the implementation file of class Book instead of in the header file.
Let's suppose the compiler sees the following code:
class Listener;
std::vector<Listener*> pListeners;
// some code...
for(auto& pListener: pListeners) {
pListener->update();
}
Note, how does the compiler see the Listener has a member function update? The symbol update could not be determined until the compiler see the Listener full declaration. Think if you used update with an argument missing, could the compiler capture this problem without seeing the declaration of update? Thus, it cannot translate the code. If you give a full declaration of the Listener, e.g.
class Listener {
public:
Listener() { // some construction
}
void update() {
// dosth
}
};
The compiler could know the update method, its parameters, the return value, etc., and compile it happily.

Using multiple structs through header files C++

Apologies if you have seen this question before however it has yet to be answered, essentially in my code I have two structs, defined in separate headers and used globally throughout the project. I simply wish to use both structs (which again, are defined in two separate headers) in other cpp files than just the ones that the header file belongs to.
Here is some sample code which I have tested:
class1.h
#include "class2.h"
#include <vector>
#include <string>
struct trans1{
string name;
};
class class1 {
private:
vector <trans2> t2;
public:
class1();
};
class2.h
#include "class1.h"
#include <vector>
#include <string>
struct trans2{
string type;
};
class class2{
private:
vector <trans1> t1;
public:
class2();
};
errorlog:
In file included from class1.h:3:0,
from class1.cpp:1:
class2.h:21:13: error: 'trans1' was not declared in this scope
vector <trans1> t1;
^
class2.h:21:19: error: template argument 1 is invalid
vector <trans1> t1;
^
class2.h:21:19: error: template argument 2 is invalid
I understand that this is ridiculous code in a real world application however this is the simplest way I could demonstrate.
It is worth noting that if I simply comment out the declaration of vector t1 or t2 under 'private:' the code compiles without fail. It is just the fact I am using a second struct.
Any help anyone? Thanks.
Simply forward-declare the classes that will be used. Put all implementation code into a cpp file, not inline in the header.
Make the vector private. This way no file that includes the header can force code generation against an incomplete class.
you can try to forward declare trans1 in class2.h and trans2 in class1.h like this:
class2.h :
// includes
struct trans1;
// rest of your code
the same thing (but with trans2) in class1.h
Don't forget to add Include guards in your code!
edit: and yes, you need to change your vectors to store pointers, otherwise it won't link
You need to put the "trans" structs in their own header file(s) and include them in your class header files.
You could forward declare them, but this would require changing your vector to use pointers. (In that case I would recommend std::vector<std::unique_ptr<trans>>). This could be appropriate if your structs are big and complex.
The main advantage of the forward-declaration approach is to reduce compile times. However if the structs are really so simple as in your example, I wouldn't bother with the extra overhead of using pointers here.
If You were to do this in single .cpp file, the solution would be trivial:
struct trans1 { ... };
struct trans2 { ... };
class class1 { ... };
class class2 { .... };
Now you just need to rearrange the code to get this result in every translation unit. (the order of classes/structs in the file is important)

How to forward declare third-party struct

In my original code, I refer to the third-party .H in the ClassOne header file and everything works fine. Now, I received a new requirement that doesn't allow me to refer to the third-party .H in the ClassOne header file. So that the consumer of my code (i.e. ClassOne) will not have to indirectly includes the third-party .H file. I have tried the following modification but it doesn't work.
Here is the sample code:
// third_party.h
struct PPP
{
int x;
int y;
}; // without default constructor
// Original code!
//////////////////////////////////////////////
// ClassOne.h // my class
#include <third_party.h> // refer to the .H in header file
namespace X
{
class ClassOne
{
...
private:
boost::scoped_ptr<PPP> m_scpPPP;
};
}
// ClassOne.cpp
#include <third_party.h>
namespace X
{
ClassOne::ClassOne()
{
m_scpPPP.reset( new PPP() ); // fine
}
...
}
// Modified code!
==========================================================
// ClassOne.h
struct PPP; // error C2371: 'PPP' : redefinition; different basic types
namespace X
{
class ClassOne
{
...
private:
boost::scoped_ptr<PPP> m_scpPPP;
};
}
// ClassOne.cpp
#include <third_party.h>
namespace X
{
ClassOne::ClassOne()
{
m_scpPPP.reset( new PPP() ); // now see errors.
// error C2512: 'PPP' : no appropriate default constructor available
}
...
}
Question 1> Where should I forward declare the third-party struct type PPP?
Question 2> Why the compiler now complain about the PPP that has no default constructor?
It is not standard behavior to instantiate templates with incomplete types, therefore it shouldn't work boost::scoped_ptr.
Having said that, unique_ptr has a special rule, allowing to take incomplete types. If you use it (instead of boost::scoped_ptr), then it is done like this :
// forward declaration of PPP, assuming c++ header
struct PPP;
namespace X
{
class ClassOne
{
...
private:
std::unique_ptr<PPP> m_scpPPP;
};
}
Simply put: That won't work. Since you use PPP (and not PPP*) in side your ClassOne, the compiler needs to know the size at that point, so it needs to know the definition of PPP. To hide PPP from the public .h file, you'll have to do more. One possible solution is to hide your implementation class behind another class. Another would be only to refer to PPP* in your class declaration (although that would make the usage of scoped_ptr<> a bit pointless).
The compiler expects a default constructor because he assumes there is one. He needs the definition of the class to call "new" as well. You can work around this problem by moving the implementation of the ctor to the .cpp file, where you may include thirdParty.h.

C++ circular include

I can't solve this circular dependency problem; always getting this error:
"invalid use of incomplete type struct GemsGame"
I don't know why the compiler doesn't know the declaration of GemsGame even if I included gemsgame.h
Both classes depend on each other (GemsGame store a vector of GemElements, and GemElements need to access this same vector)
Here is partial code of GEMELEMENT.H:
#ifndef GEMELEMENT_H_INCLUDED
#define GEMELEMENT_H_INCLUDED
#include "GemsGame.h"
class GemsGame;
class GemElement {
private:
GemsGame* _gemsGame;
public:
GemElement{
_gemsGame = application.getCurrentGame();
_gemsGame->getGemsVector();
}
};
#endif // GEMELEMENT_H_INCLUDED
...and of GEMSGAME.H:
#ifndef GEMSGAME_H_INCLUDED
#define GEMSGAME_H_INCLUDED
#include "GemElement.h"
class GemsGame {
private:
vector< vector<GemElement*> > _gemsVector;
public:
GemsGame() {
...
}
vector< vector<GemElement*> > getGemsVector() {
return _gemsVector;
}
}
#endif // GEMSGAME_H_INCLUDED
Remove the #include directives, you already have the classes forward declared.
If your class A needs, in its definition, to know something about the particulars of class B, then you need to include class B's header. If class A only needs to know that class B exists, such as when class A only holds a pointer to class B instances, then it's enough to forward-declare, and in that case an #include is not needed.
If you deference the pointer and the function is inline you will need the full type. If you create a cpp file for the implementation you can avoid the circular dependecy (since neither of the class will need to include each others .h in their headers)
Something like this:
your header:
#ifndef GEMELEMENT_H_INCLUDED
#define GEMELEMENT_H_INCLUDED
class GemsGame;
class GemElement {
private:
GemsGame* _gemsGame;
public:
GemElement();
};
#endif // GEMELEMENT_H_INCLUDED
your cpp:
#include "GenGame.h"
GenElement::GenElement()
{
_gemsGame = application.getCurrentGame();
_gemsGame->getGemsVector();
}
Two ways out:
Keep the dependent classes in the same H-file
Turn dependency into abstract interfaces: GemElement implementing IGemElement and expecting for IGemsGame, and GemsGame implementing IGemsGame and containing a vector of IGemElement pointers.
Look at the top answer of this topic: When can I use a forward declaration?
He really explains everything you need to know about forward declarations and what you can and cannot do with classes that you forward declare.
It looks like you are using a forward declaration of a class and then trying to declare it as a member of a different class. This fails because using a forward declaration makes it an incomplete type.

how to use not yet defined datatypes in a header?

I am programming on linux using g++ and I often encounter the problem that I need to use a class or data type in a header file which I define later, either at a later point in the header or in another header file.
For instance look at this header file:
class example
{
mydatatype blabla;
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
This will give error because mydatatype is used before its defined
so usually I change it like this:
struct mydatatype; // <-- class prototype
class example
{
mydatatype *blabla; // <-- now a pointer to the data type
// I will allocate the data during runtime with the new operator
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
Now it works. I could often just put the definition above, or include the header which is needed, but I don't want to include headers in a header or juggle with the definition order, it always gets messy.
The solution I showed usually works, but now I have encountered a new phenomenon. This time the datatype is not a class but a typedef, I cant use prototypes for a typedef and I don't want to use the actual datatype which the typedef incorporates.. it's messy too.
Is there any solution to this?
Firstly, the solution you've thought of (prototype and pointer), is unneeded, and slower than just implementing it without the pointer.
The "proper" solution for this, would be creating seperate headers for each type, and then include them in your other header. That way it will always be defined! You can even make them so that they include eachother.
However, if you've ever opened a .h file provided by g++, you've most likely seen this at the start of the header:
#ifndef SOMETHING_H
#define SOMETHING_H
// Code
#endif /* SOMETHING_H */
This is to solve the issue of types redefining themselves.
If they weren't there, and you included the header file multiple times, the types would be redefined, and an error would be thrown. This makes it so that the types are always present, but never included twice.
I hope that helps!
Place each class/type in it's own header file, and then include the relevant header file in other headers where you need it. Use an inclusion guard in each header e.g.:
// SomeHeaderFile.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// code
#endif
I disagree that this is messy - it allows you have an organised structure to you project, it allows each class to operate independently of others and without worrying about order, and it's a good idea to place each class in it's own file anyway.
You could just define the class inside the other class like
template<class T>
class vertex {
private:
class edge {
public:
vertex<T> *to;
double weight;
edge() {
weight = INFINITY;
to = NULL;
};
} *paths;
T data;
unsigned nof_paths;
public:
vertex(T val) {
data = val;
paths = NULL;
nof_paths = 0;
}
void addPathTo(vertex<T>*&);
edge* getAllPaths() {
return paths;
};
};
Obviously this works for small classes... if your class is ENORMOUS you'll be better using separate header files like the other guys said.