I'm having an issue writing a class as part of a C++ program - in it I have three classes, FirstClass, SecondClass, and ThirdClass - First and Second classes both include ThirdClass.h, and in SecondClass I can declare them normally, however, in FirstClass the first declaration works fine, but any further declarations give me an error that "ThirdClass is not a type name"
here's a snippet from the class that's erroring
#include "ThirdClass.h"
class FirstClass
{
public:
FirstClass(void);
// This decleration of ThirdClass works fine
FirstClass(ThirdClass ());
FirstClass(const FirstClass& rhs);
~FirstClass(void);
private:
//These are the two that're erroring
ThirdClass nestedClass();
void Init (ThirdClass ());
void Copy (FirstClass);
};
I'm assuming that it's something to do with both of them linking to the same header file, but i've been looking far and wide trying to find a solution online to no avail.
I did manage to get it working by placing the include inside a namespace, but I also read that this was very bad practice so I don't really want to do it that way.
FirstClass(ThirdClass ());
What is this supposed to do?
If the type ThirdClass has been declared then it declares a constructor that takes the address of a function as its argument, that's not what you wanted, right? ThirdClass () is the type of a function that takes no arguments and returns a ThirdClass, so your constructor argument is (the address of) a function of that type.
If ThirdClass hasn't been declared (and the error you're getting implies it hasn't been) then it is equivalent to:
FirstClass ThirdClass();
i.e. a (non-constructor) function called ThirdClass which returns a FirstClass object.
You probably wanted it to be a constructor taking a ThirdClass object as the argument, which would be:
FirstClass(ThirdClass);
Or to avoid copying the argument (which is usually what you want):
FirstClass(const ThirdClass&);
Similarly for your Init function.
The errors saying ThirdClass is not a type name indicate the type hasn't been declared. We can only guess because you didn't show a complete, self-contained example (no cookie for you) but you probably have #include "FirstClass.h" in your ThirdClass.h header, which causes circular reference and only one of the files is processed correctly.
See these questions (and their answers) for more:
cyclic dependency between header files
C++ cyclical header dependency
C++ error: 'Line2' has not been declared
I guess, your constructor and Init() should be
FirstClass(const ThirdClass &rhs);
...
void Init (const ThirdClass &rhs);
Furthermore, you should consider adding include guards.
Related
I'm fairly stupid when it comes to C++ as I'm from a pure Java background with good Python knowledge, but I am trying to make a simple C++ class with a vector referenced in the header file, and access it in a function in the source file. I can access it fine in the constructor, however as soon as I use a function, it apparently doesn't exist according to Eclipse CDT, and the build chain.
Header file (simulator.h):
#ifndef GAME_PHYSICS_SIMULATOR_H_
#define GAME_PHYSICS_SIMULATOR_H_
#include <vector>
#include "../world/object.h"
class simulator {
public:
simulator();
virtual ~simulator();
void add_object(object o);
private:
std::vector<object> objects;
};
#endif /* GAME_PHYSICS_SIMULATOR_H_ */
Source file (simulator.cpp):
#include "simulator.h"
simulator::simulator() {
object o;
objects.push_back(o); // Works fine in terms of acknowledging the existence of 'objects'.
}
simulator::~simulator() {}
void add_object(object o) {
objects.push_back(o); // Immediately throws error saying 'objects' doesn't exist.
}
The funny thing is though, is that I can access things like int's or std::string's fine. As soon as I try to use the vector it breaks. Any ideas?
Use simulator::add_object since it's a class method, just like you did for the constructor and destructor already.
Compared to Java you can define functions outside of the class definition (like in an extra .cpp file, which is usually encouraged to do so), in this case you have to prepend class_name:: to the function signature.
If not, because your function is not in the class namespace, it becomes a non-member function (meaning a function which belongs to no class) and it does not know the objects member which is inside your simulator class.
A problem I'm working on is asking me to define an istream constructor inside the class body. Let's call the class Sound. Now this constructor uses a function in its own body. But the function is supposed to be a non-member function. I have it defined in another file, but I have it declared in the header that contains the class definition itself. I've placed the header in the other file containing the non-member functions already.
The problem is, one of the parameters of the non member function has type Sound and it performs operations on the type Sound objects.
When I declare this function in the header file, if I put it before the class definition I get an error saying the objects haven't been defined.
When I put the declaration after the definition, the constructor now tells me that the function inside it's body is undefined.
If I put the declaration inside the class body, it becomes a member function.
The problem didn't explicitly state that I cannot make the function a member function so I am wondering if there is a way to overcome this catch-22.
You do not necessarily need to make the function member. You can have at least two ways to solve it in a different manner.
The problem is that you are having all this in a situation where a Sound object is not yet defined if I understand correctly.
1) You can refactor your code a bit as demonstrated below.
header file:
class Sound
{
public:
Sound();
doStuff();
}
cpp file:
void non_member_function(Sound sound)
Sound::Sound() { non_member_function(*this); }
Sound::doStuff() {}
void non_member_function(Sound sound) { sound.doStuff(); }
2) if you insist on the scenario aforementioned, you put a Sound sound forward declaration before the non-member function to get the type recognized. Or, you can just put the declaration after the class declaration.
header file:
class Sound
{
public:
Sound();
doStuff();
}
void non_member_function(Sound sound)
cpp file:
Sound::Sound() { non_member_function(*this); }
Sound::doStuff() {}
void non_member_function(Sound sound) { sound.doStuff(); }
Looks like best thing to do is to use forward declaration for class, before the function:
header:
class Sound;
void f(Sound s);
class Sound
{...};
In c++ you can define a function as a member function or a non-member function. If it is not specified or required that the function be define as member or non-member as you have pointed out, then I would opt for an easy or simple solution.
Calling a non-member function within a constructor might require you, to use a certain technic to go about this function call, now that might not be required if the function was defined as a member function.
I am working on a codebase that is not my own, that has the following layout:
object.h:
// Objects are defined
// #include "tickets.h" (functions to access the objects)
// An access-handler object is defined
I want to introduce a class that knows about the objects, can be accessed from functions in tickets.h, but can also use the access-handler object. The functions are separate, i.e. class functions that are called in tickets.h do not use the access-handler (I wouldn't know where to start if that weren't the case).
Therefore my class needs to be defined before tickets.h, but some of its functions need to be defined after the access-handler. Is there a way to do this without splitting it up into two header files something like the following:
// Objects are defined
// -- include declaration of class, and definition of functions that tickets.h needs
// #include "tickets.h"
// An access-handler object is defined
// -- include functions of class that need the access-handler
This seems very messy splitting things up like this into two separate files, I was hoping to keep everything contained.
Thanks for any help, I clearly only have a very rudimentary understanding of declarations/definitions in c++.
EDIT: If I use forward declaration and include it before tickets.h (with the class declared in mynewclass.h and functions defined in mynewclass.cc) will mynewclass.cc be able to use objects declared after the inclusion of mynewclass.h? Namely the access-handler object.
EDIT2: Something like this:
object.h:
class obj { // definition }
#include "tickets.h"
class obj_handler {
public void handle { // code }
}
tickets.h:
void do_something(obj o){
communicator.foo();
}
My object (communicator):
class communicator {
public:
void foo() { // code }
void bar() { // use handle() from obj_handler }
}
As you can see, my communicator needs to be used in tickets.h, but can't be defined until after obj_handler. So where should I include it?
If I correctly understand your question - you can use forward declaration to solve this problem. This will allow you to declare some class before defining it's methods. For example:
// this is forward declaration of class A, no definition provided
class A;
class B
{
// uses A
A * a_;
};
// class A definition
class A
{
// may use class B now
B * b_;
};
I'm not quite sure whether I understand this right and don't have enough reputation here yet to make this a comment, so let me try to answer your question this way, please feel free to follow up if I'm guessing wrong:
I believe what you are referring to is an entire class definition, i.e., one including all function definitions within the class declaration. Other than that, it is not very common to see object definitions followed by preprocessor directives. What is typical though is a forward declaration of functions and a class prototype.
So, for example, you could declare in some header.h:
class C
{
public:
void method1(void);
int method2(void);
};
And in some implementation.cpp the definition of the functions like:
void C::method1(void) { /*...*/ }
In the other file preceded in the inclusion chain by your access-handler you then define the other function:
int C::method2(void) { /*...*/ }
What do you mean by access-handler, by the way?
Oh, and your linker likely will yell somewhat at you if you do function definition in a header file.
With regard to your addenda: everywhere you put a forward declaration, loosely speaking, the compiler will insert a copy of the declaration in question, consider it a soft link in the context of file systems. There are negative implications associated with it, like increased duration and the memory load of compilation if you have many forward declarations of the function signature or class. It's impossible to tell whether this will word in your particular situation since only you know the actual code in question. But most likely it would work.
Take a look at these pages:
http://en.wikipedia.org/wiki/Forward_declaration
When can I use a forward declaration?
I want to reimplement a library of which I have the header file.
I would prefer not to change the .h file since that would require changes in the programs that use the library (plus some legal reasons).
EDIT: I also cannot change the code that uses the library and instantiates class X!
the lib.h defines a class X (simplified version):
class X
{
public:
bool Function(BOOL q, INT p);
BOOL a;
INT b;
};
(BOOL and INT are just some datatypes used by the library, these classes wrap a primitive data type of bool and int).
I implemented this class in my_lib_implementation.cpp:
bool X::Function(BOOL q, INT p)
{
return true;
}
The .h file does not define a constructor, so this means that there is an implicit constructor (right?).
Problem is, I need to initialise the variables a and b for my implementation of Function(BOOL q, INT p) to work correctly.
However if I add the following, I get compile errors ("error: definition of implicitly-declared 'X::X()'", gcc 4.4):
X::X()
{
a=true;
b=0;
}
Is it possible to overload the constructor through some magic that I do not know about? Are there other options for initializing the variables?
There is a an implementation of the library (that I can't use), so it seems like it should be possible somehow?
I only just started programming C++ this week (I do have extensive experience with other languages), so this problem is probably just my lack of basic knowledge.
Hope you guys can help me out!
No, it's not possible, the compiler-generated default constructor cannot be overloaded.
You can however initialize the members with the following syntax:
X x = {true, 0};
There isn't really a way to directly do what you're asking. (Provide a default constructor without declaring it in the class.)
The closest you can come to this is to also redefine the BOOL and INT classes, assuming those have defined default constructors. If they have, then you can change the meaning of the default to whatever you want.
Alternately, you could completely change the behavior of the function. You can add members to the class, including for example something to keep track of whether the function has been called yet, or how many times, etc. Or you could define your own betterthanX member and just forward the function calls to the member, and then copy out the results back into the members of the real X class.
A very dirty hack could be to define a preprocessor macro just before including the library header file that changes X to X_. You can then define your own X that inherits from X_ and defines whatever constructor you like. You should #undef the macro after the #include. Don't blame me if you run into insidious bugs.
I am trying to do the following: Obtain the address of a member function from a class that was locally defined within a function.
class ConnectionBase
{
};
template class<EventType, SinkType>
class ConnectionImpl : public ConnectionBase
{
public:
typedef void (SinkType::*EventCallback)(EventType const&);
};
template<class EventType>
class Source
{
template <class SinkType>
boost::shared_ptr<ConnectionBase> setupCallback(typename ConnectionImpl<EventType, SinkType>::EventCallback func, SinkType* sink)
{
// do the actual connecting.
}
};
class SomeClass
{
public:
void someFunction(int const& event){}
}
class SomeUnitTest
{
public:
void someTest()
{
class NestedClass
{
public:
void someFunction(int const& event){}
};
NestedClass nc;
//Try#1 - This does not work
setupCallback<int, NestedClass>(&NestedClass::someFunction, &nc);
//Try #2 - This also does not work
setupCallback<int, NestedClass>(&SomeUnitTest::someTest::NestedClass::someFunction, &nc);
//Try #3 - Following the GCC error output, I tried this
setupCallback<int, NestedClass>(&SomeUnitTest::someTest()::NestedClass::someFunction, &nc);
SomeClass sc;
//This works fine, as expected
setupCallback<int, SomeClass>(&SomeClass::someFunction, &sc);
}
};
Try #2 and #3 utterly confuse GCC, it has no idea what I am trying to do.
Try #1 produces a more helpful error message saying no setupCallback exists that takes the form "setupCallback(void (SomeUnitTest::someTest()::NestedClass::SomeFunction::*), etc)
Which is how try #3 was born.
I can't really find a lot of information about classes defined inside a function, does anyone know the correct syntax for this, and maybe have a resource that discusses this topic?
Ok, it appears this is settled, as both posters have pointed out, local classes have no linkage, it can't work. Now knowing this, I found this article that discusses this, for anyone else that runs into this problem and stumbles across this question: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=420
Edit:
Clarification of setupCallback(), working example with a more regular class
Edit #2:
Updated wording to change "nested" to "local". Added more detail for setupCallback.
Edit #3: Added links to furhter information. Thanks everyone.
I don't know about the syntax problem, the usual access rules should apply - but there is another problem here if that would work as these member functions have no linkage.
To accept local types at all, setupCallback() would have to be a template function - but template type arguments with no linkage are not allowed.
§3.5/8 says:
Names not covered by these rules have
no linkage. Moreover, except as noted,
a name declared in a local scope
(3.3.2) has no linkage.
Members of local classes are not covered there. §9.3/3 clarifies that:
Member functions of a local class
(9.8) have no linkage.
Long story cut short: don't use member functions of a local class as callbacks, use a non-local class instead.
You fist variant is the correct one as long as the specific matter of taking the address is considered. There are no restrictions on taking the address of member functions of local classes. The proper syntax is the usual
&NestedClass::someFunction
ans that's it. You can try saving it in an intermediate pointer in your code
void (NestedClass::*ptr)() = &NestedClass::someFunction;
and I'm sure your compiler will accept it.
However, the problem I suspect exists in your code has absolutely nothing to do with the proper way of taking the address of a member function. It is rather about the way the first parameter of setupCallback is declared. Since you say it works with &SomeClass::someFunction as the first argument, I'd expect setupCallback to be declared as
void setupCallback(void (SomeClass::*cb)(), SomeClass *p); // one possibility
i.e. it is hardcoded to expect a pointer to a member of SomeClass specifically. You cannot supply a pointer to a member of NestedClass instead. NestedClass is completely unrelated to SomeClass and pointers to members of NestedClass are completely incompatible with pointers to members of SomeClass. This is why it won't compile.
Unless there's something you are not showing us (like setupCallback being a function template maybe? Or overloaded for different parameter types?), what you are trying to do is simply impossible to achieve regardless of how you take the member address, as long as NestedClass remains unrelated to SomeClass. Function setupCallback is designed to work with SomeClass and SomeClass only.
Provide more information about setupCallback. How is it declared?
Note that if the setupCallback is declared as a function template parametrized by class type, as in
template <class T> void setupCallback(void (T::*cb)(), T* p);
then you won't be able to use the local class NestedClass as template argument for parameter T. In this case the fact that your NestedClass has no linkage does indeed come into play. But, again, it has nothing to do with taking the member address, but rather caused by the fact that classes with no linkage cannot be used as template arguments in C++.