I have a class whose declaration is getting too bloated for a single header file. I nest classes and structures within it to reinforce their relationship together, so I'd like to keep them together (in the sense that I must use the outermost class's namespace to use the classes within)
Is there a way to declare nested classes from another header file? Or perhaps at least declare the methods of the nested class in another header file? (many methods per class is the reason for the bloat, the number of classes is relatively reasonable at 10)
The structure looks a bit like this:
class Stage{
class Quad{
Quad();
Quad(int width, int height);
// like 20 different constructors, plus methods
private:
glm::vec3 p[4];
};
class Line{
// ...
};
// and a bunch of other classes
// Stage methods
void draw(Quad quad);
void draw(Line line);
// ...
};
I should probably add, I can't expand them inline with the preprocessor, since that messes up my IDE's code completion if I get creative with it.
Is there a way to declare nested classes from another header file?
No, nested classes can only be declared in their surrounding class definition.
Or perhaps at least declare the methods of the nested class in another header file?
Yes, you can just declare the nested classes within their class, then define them later.
class Stage{
class Quad;
class Line;
// and a bunch of other classes
// Stage methods
void draw(Quad quad);
void draw(Line line);
// ...
};
// ... later
class Stage::Quad {
// stuff
};
// ... later still
class Stage::Line {
// whatever
};
Related
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?
This is a question that troubles me a for a while, but could not find a the best way to deal with it. I am trying to show this through an example.
I am developing a graphics library with many classes. Some of the classes are "part of" relationship with each other, like these 3 classes:
namespace MyGraphicsLibrary
{
class MatrixStack
{
};
class Transform
{
MatrixStack mMatrixStack;
};
class Renderer
{
Transform mTransform;
};
}
The Renderer class is for users to use, but i did not want them to see Transform, MatrixStack classes when they lookup the MyGraphicsLibrary. The last two classes are only for Renderer class and not for users to use.
Here i am trying to do two things:
Hiding the Transform, MatrixStack classes from users.
Reflect the "part-of" hierarchy of the classes.
I tried the followings to solve this:
The best solution for me would be the private nested-classes, as it would show the user that the nested class is private and also reflects the hierarchy if you simply look at the Renderer class declaration. The following post actually makes me uncertain that is good solution: Pros and cons of using nested C++ classes and enumerations?
I tried to put Transform, MatrixStack into another namespace called Private. So user looking up MyGraphicsLibrary namespace would see Private namespace only covering all classes which are not for the users.
That's good, but there are lot of other classes with the same issue, and i quickly fill the Private namespace with classes which has nothing to do with each other.
Here I could only come up with ugly solutions, like introducing nested namespaces:
namespace MyGraphicsLibrary
{
//private classes belonging to Renderer class
namespace PrivateRenderer
{
class MatrixStack
{
};
class Transform
{
MatrixStack mMatrixStack;
};
}
//public classes for users
class Renderer
{
Transform mTransform;
};
}
Maybe I miss something here, but what do you think which one is the way to go.
Does anybody has a 3rd way?
you can use the PIMPL- (also called opaque pointer) idiom.
with hat you can entirely hide the classes from user the following way:
In your public header (in your include folder):
Renderer.h
class RendererImpl; // forward declaration of internal render structure
//public classes for users
class Renderer
{
public:
Renderer();
~Renderer();
// public interface comes here and delegates all calls to RendererImpl (have to be implemented in cpp)
RendererImpl* renderer; // better use something like QScopedPointer here
};
the cpp:
#include "RendererImpl.h" // your actual renderer that
Renderer::Renderer()
:renderer(new RendererImpl)
{}
Renderer::~Renderer()
{
delete renderer;
}
The implementations may be completely hidden from the API. The headers have to be separated from the real interfaces.
If you want to store Transform as a plain (non-pointer/reference) member, then for the compilation of your public header, its definition should also be visible, because it affects the layout of the container class.
Consequently, the type will be visible wherever you want to use the container class.
You have the following options:
Signal that they are not for public use through naming. Either by putting into a namespace (like detail in boost), or prefixing/suffixing its name.
Use a technique that prevents clients from using that class. Make every member functions private and declare the container class friend. The attorney-client idiom is a more sophisticated way of fine-grained access control.
Store Transform indirectly (pointer or reference), so you do not need its definition in the public header. This is pimpl. A variant of this if the public type is an interface, a base class of the actual Transform implementation.
Unnamed namespace: definitely a bad idea in a header. Unnamed namespaces are like C static: they get a compiler-generated identifier that is guaranteed to be unique to the given translation unit. You will end up with as many distinct Transform types as many places you included its definition.
Use an anonymous namespace:
namespace MyGraphicsLibrary
{
namespace
{
class MatrixStack
{
};
class Transform
{
MatrixStack mMatrixStack;
};
}
class Renderer
{
Transform mTransform;
};
}
I have started reading C++ and I have a question about classes and member variables of type Enum and Struct. Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file? And also, how can I make a final member variable in a C++ class? I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
The header file is like a person saying 'I can do this, that and the other' - so put declarations into it - enums, structs, class declarations, constants, ...
The implementation file is like a person saying 'I can do this and this is how I can do it' - it produces a recipe - Actual machine code for the CPU to crunch.
const says - do not change me. To intialise in a class you need:
class X
{
private:
const int y;
public:
X() : y(5) {}
};
for example. If you are learning about C++ const is a very useful tool to prevent you making a multitude of errors.
the simplest solution is to simple declare the enums & structs directly before the class they are a member of:
struct Gizmo
{
int n_;
};
class Foo
{
public:
Gizmo gizmo_;
};
If Gizmo is logically coupled to Foo (eg, if you would never use a Gizmo outside the context of using a Foo), it might also make sense to make Gizmo a nested class:
class Foo
{
public:
struct Gizmo
{
int n_;
};
Gizmo gizmo_;
};
If you want to instantiate a Gizmo declared this way, you can resolve the scope yourself:
Foo::Gizmo gizmo;
Finally, if Gizmo and Foo are not logically coupled, and you might use Gizmos all over the place without needing a Foo, then it probably belongs in its own header file.
gizmo.h
struct Gizmo
{
int n_;
};
foo.h
#include "gizmo.h"
class Foo
{
public:
Gizmo gizmo_;
};
Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file?
You must declare them before their use, that is. before the declaration of the member in the class of their type. Either:
you define them in their own header file and #include that file in your class' header file (before the declaration of your class)
or you define them just before your class
or you define them in your class before the members
I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
In the constructor, using initializers. Ie.:
Clazz::Clazz() : my_const_var(0) { ... }
If you're going to add an enum or struct as a member variable of the class, the definition of the enum or struct must be complete before you declare the member. This can either be inside the class, outside of the class but coming before it in the .h header, or in a different .h header that is included before or within the current one.
There shouldn't be any problem declaring a member variable as const, but it places a restriction on how it must be initialized. You must do it in the initializer list of the constructor.
MyClass::MyClass() : myTest(value)
{
}
It is possible to declare a class without defining it (forward declaration) as long as it is defined later on within the translation unit. In the case of functions, one can declare a function without defining it within the translation unit, and the linker will link it to its definition in a different translation unit. Is it possible to do the same with class declarations?
(if this is not possible, is there any use to a forwardly declared class without a definition in the current TL, or is that always an error?)
something like this, except this doesn't compile:
mymain.cpp:
class myclass; // declare without defining
myclass::myclass();
void myclass::barf();
int main() {
myclass *m = new myclass();
m->barf();
return 0;
}
myclass.cpp:
#include <iostream>
class myclass { // define the implementation
public:
myclass();
void barf();
};
myclass::myclass() { } //empty constructor
void myclass::barf() {
std::cout << "barfing\n";
}
It is possible to forward-declare a class, but only pointers and references to forward-declared classes can be used. You can't use an actual object of a forward-declared class because the compiler doesn't know enough about it; in particular it doesn't know how large the object is or what its members are. Trying to forward-declare member functions (as you have done) won't work because the syntax of the forward declaration doesn't allow you to specify whether the functions are virtual or non-virtual (or perhaps inherited from some base class).
It is not often useful to forward-declare a class in a source file, but it can be useful in a header file. In particular it's common to forward-declare a class in a library's public header file and use pointers to that type as opaque handles. The class definition remains private to the library but user code can pass around pointers to objects of that class without ever knowing what the class's implementation looks like. This works particularly well when the pointers are smart pointers.
You can, but only if you use exclusively pointers or references to that class. But you can't use code referring to that class' members (variables or methods). You can only use it to declare pointer variables to that class.
I would suggest you create a myclass.h header file with myclass' full declaration, and include that header in mymain.cpp.
You can only do that through hacks.
The declare before use rule doesn't hold within a class (see here).
Otherwise you can do that by declaring your function as a template function, whose template parameter is of myclass (in your example).
The only non-hack way is to define the class (ie. by including the header file its defined in).
I have a program that uses enum types.
enum Type{a,b,};
class A
{
//use Type
};
class B
{
// also use that Type
};
2 class are located in 2 different files.
Should I put the type definition in a headfile or
in class definition for each class?
If the enum is going to be used in more than one .cpp file, you should put it in a header file that will be included by each. If there's a common header file, you should use that, otherwise you may as well create a new header file for this enum
You should always attempt to limit the scope of types in C++, so the enum should probably be declaread at class scope. The enum will typically belong slightly more naturally in one class than the other - lets say class A, so you put it in the declaration of A in the a.h header:
// a.h
class A {
public:
enum Type { a, b };
...
};
Now you need to include a.h in the header that declares B:
// b.h
#include "a.h"
class B {
public:
void f( A::Type t ); // use the Type enum
...
};
I can see the point of Neil: it is a pet peeve for many programmers to see stuff on the global scope. otoh, imho, introducing a class just for an enum is not a good style: It is supposed to be enum not a class. However, putting the same enum list in both classes (is what you were asking) would be the worst idea: we don't want to be repeating stuff.
Moreover, in most non-trivial codes, one might end up using more of such shared entities (more enums, const parameters, etc...) for implementation. So, I'd begin lumping all this into an implementation namespace (say "detail") which is a child namespace of your classes, and resides in a separate header file (say "detail.hpp"), included by all. For example:
// file A.hpp
#include "foo/detail.hpp"
namespace foo {
class A
{
// accessing enum as detail::a
};
}
// file B.hpp
#include "foo/detail.hpp"
namespace foo { class B { ... }; }
// file foo/detail.hpp
namespace foo { namespace detail {
enum { a,b, ... }
const int three = 3;
// etc...
// other implementation classes etc...
}}
And "detail" is nice and clean way of warning your class users to back off from whatever's declared in there. As your code gets bigger and these implementation details start growing in number you can break the dependencies into separate header files (detail1 detail2 etc...) and still keep one "detail" namespace (something which you can not do with a "class detail" for example).
The question is rather vague, but as a rule of thumb, you should try to minimize the redundancy in your code. Therefore, you should put the declaration of the enum to a header file.
It really depends on if the values are the same logical type, or if they just happen to have the same names. Would it make sense to assign an A::Type variable to a C::Type? If they are the same logical type, put them in a header that both include. To keep your build times low you probably want to put it in its own header file, but putting it in a shared header with other stuff works if you want to keep the number of files down.
Another option is to put the enum in a common base class that both inherit from (this may not make sense in this case, but it is another option).