5

I saw this constructor:

MyClass(class MyOtherClass* = 0) {}

What does the class keyword mean? Does the constructor take a MyOtherClass pointer and defaults the argument to the null pointer?

Andreas
  • 7,470
  • 10
  • 51
  • 73

1 Answers1

10

It's a forward declaration. MyOtherClass doesn't have to be defined before use in this context, so a forward declaration is enough. The =0 is the default value for the argument.

Braindump of the cases where you don't need a full definition:

  • member pointers
  • member references
  • method parameter types
  • method return types

Compare the following:

//MyClass.h
class MyClass
{
    MyClass(MyOtherClass* = 0) {} //doesn't compile
                                  //doesn't know what MyOtherClass is
};

//MyClass.h
class MyClass
{
    MyClass(class MyOtherClass* = 0) {} //compiles, MyOtherClass is declared
};

//MyClass.h
class MyOtherClass;   //declare MyOtherClass
class MyClass
{
    MyClass(MyOtherClass* = 0) {} //compiles, declaration available
};
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Just a clarifying point. `MyOtherClass` doesn't have to be fully defined here because all that is needed is a pointer to it. A forward-declare tells the compiler everything it needs to know about `MyOtherClass` in order to generate a pointer to it. – John Dibling Oct 10 '12 at 14:38
  • @JohnDibling not restricted to a pointer. In this case it works because it's a parameter. You only need a full definition for an object member as far as I know (pointer members, references, parameters & return types don't require a full definition). – Luchian Grigore Oct 10 '12 at 14:39
  • Why would I want to do that if I could simply include the header file that declares `MyOtherClass`? – Andreas Oct 10 '12 at 14:39
  • 1
    @Andreas: because you want to minimize your includes. –  Oct 10 '12 at 14:40
  • @Andreas forward-declarations are to be preferred. – Luchian Grigore Oct 10 '12 at 14:40
  • @Andreas: You might not want to include the header file. As for whether or not this is good style by default is a matter of opinion, but I think not. If you can include the header, include the header. – John Dibling Oct 10 '12 at 14:40
  • @Andreas see http://stackoverflow.com/questions/9906402/should-one-use-forward-declarations-instead-of-includes-wherever-possible/9906429#9906429 – Luchian Grigore Oct 10 '12 at 14:40
  • @JohnDibling not only a matter of opinion, there are compelling arguments to prefer forward-declarations. – Luchian Grigore Oct 10 '12 at 14:41
  • @JohnDibling: there are many compelling arguments in favor of forward-declarations; however I much prefer forward-declaring at the top of the files, right after the includes, rather than doing it in the middle of nowhere... – Matthieu M. Oct 10 '12 at 15:17
  • @MatthieuM. definitely, the syntax in the question is awful if you ask me. :) – Luchian Grigore Oct 10 '12 at 15:18
  • 1
    The usual gotcha with forward-declaring things in preference to including the appropriate headers, is when the type turns out not to be easily forward-declarable `std::string` is an example of the kind, not that you could forward-declare *anything* into namespace `std` anyway, even if it weren't a typedef for an instantiation of a template. But the point is that you can't forward-declare `class Foo;` unless `Foo` is defined by `class Foo { ... };`. IMO forward-declaring types from other people's modules is an unacceptable abstraction leak, YMMV. – Steve Jessop Oct 10 '12 at 15:23
  • http://www.gotw.ca/gotw/034.htm for a little more info, albeit using `std` examples again but the same problem would occur anywhere that a module provides a type name that isn't *necessarily* the name of a class. If a module thinks users need a "light" version of its header containing only forward-declarations, then it should do so itself. – Steve Jessop Oct 10 '12 at 15:28
  • @SteveJessop of course, **but** in this case it is possible. And that's what I'm dealing with & explaining in the linked answer - that one should prefer forward-declarations where they are possible. – Luchian Grigore Oct 10 '12 at 15:31
  • @Luchian: I'm responding to "forward-declarations are to be preferred" rather than this answer as a whole, which is fine. The reason forward-declarations are *not* to be preferred IMO is that just because the user of the module thinks they're possible doesn't necessarily mean that the *author* of the module realizes that you're relying on it. If the module documents, "this type name is a class name" (or equivalent) then fine, otherwise you're inappropriately coupling to an implementation detail. – Steve Jessop Oct 10 '12 at 15:33
  • @SteveJessop I might be slow right now, but I still don't fully see a case where an include is better where a forward-declaration is a valid option. If you add an answer to that question explaining (please do, I'd love to understand), ping me. – Luchian Grigore Oct 10 '12 at 15:39
  • @Luchain: well, there's already an example in anatolyg's answer on that other question, where a forward declaration is valid but constitutes significant code duplication. – Steve Jessop Oct 10 '12 at 15:40
  • @SteveJessop I see. That's a fair point, but, in my (point's) defense, you'd still get prompted of an error when you include the header in a cpp file (class redefinition), so you can easily change it to match the definition. But yes, templates are tricky if they are subject to change. – Luchian Grigore Oct 10 '12 at 15:44
  • @SteveJessop well, I'm relying on that because if you don't include it, that means you don't need or use anything that's defined inside. – Luchian Grigore Oct 10 '12 at 15:47