C++ - why does this member need to be declared static?
This was driving me insane. I was getting a "No matching function call to 'WordCloud::WordCloud()'" error. It seems that a default constructor was being called, but because I didn't define one, the error was being thrown.
The constructor is:
WordCloud( map<string, int> *source );
And in the main cpp file, the error was occurring on the indicated line
class FontTestingApp : public AppBasic
{ // <-- error was appearing on this line
public:
void setup();
void mouseDown( MouseEvent event );
void update();
void draw();
map<string, int> wordList;
WordCloud wc; // comment out this line and it compiles
};
So, I'm guessing a WordCloud object was being instantiated when the FontTestingApp class was instantiated.
If I comment out the line
Wor开发者_如何学PythondCloud wc;
Then it compiles.
To fix it I finally changed the line to
static WordCloud wc;
And that compiled.
I really don't know why, though, and that's not good enough :) If someone could explain what's going on here I'd be very grateful. I'm using libCinder by the way (libcinder.org)
Non-static member variables in a class are instantiated (ie, their constructors are called) when the containing object is constructed. By default, the zero-argument default constructor is called - but the compiler only provides this for you if you do not provide any explicit constructors.
The solution is to explicitly construct the wc
object in the FontTestingApp constructor:
FontTestingApp::FontTestingApp()
: wc(&wordList)
{ /* ... */ }
As for why the static
change suppressed the error, the declaration static WordCloud wc;
in the class definition does not instantiate the object; it merely declares it, in exactly the same way that an extern WordCloud wc;
at file scope would not instantiate the class. Indeed, static member variables are essentially the same as extern
globals, except that their name and access control rules are based on the class they are in.
Had you actually instantiated the static member variable in some .cpp
file with:
WordCloud FontTestingApp::wc;
Then you would have got an error. Of course, you could pass in constructor parameters to resolve this:
static map<string, int> dummy_word_source;
WordCloud FontTestingApp::wc(&dummy_word_source);
Note that if you don't instantiate the variable at all, you will of course get a linker error if you attempt to reference it elsewhere.
Your guess about why the compiler was looking for the default constructor is correct; you don't explicitly call the relevant WordCloud
constructor in an initializer list in a FontTestingApp
constructor.
As for why the static
approach "works"; it doesn't. Static member declarations must also be accompanied by definitions (typically along the lines of WordCloud FontTestingApp::wc(/*args*/);
in a CPP file somewhere. Without out that, no object is instantiated, and hence no constructor is called.
Note: as I'm sure you're aware, the semantics of a static class member are very different to those of a non-static member.
Because you have provided the custom constructor (for WordCloud
), the compiler no longer generates the default ctor.
If WordCloud
is not your class, then you have ensure that in all your constructors (including a default one for class FontTestingApp
) you construct the member correctly in the initializer list.
If you declare constructor with parameters and wanna use constructor without parameters you must declare the last explicitly. But you don't use wc constructor with parameters. If you wanna do this, you must write something like this:
class FontTestingApp : public AppBasic
{
public:
...
FontTestingApp() : wc(&wordList) {}
map<string, int> wordList;
WordCloud wc;
};
Using "static" statement is only declaration of data member but not definition. That's why your code compiled without errors.
You have to define a default constructor if you are using a non-default one. When the member is static, no memory is allocated for it until you explicitly define it (as opposed to declaring it), that's probably why you didn't get the error.
The problem, I'm guessing, is that the WordCloud class doesn't have a default constructor. Consequently, if the compiler auto generates a default constructor for FontTestingApp, it will try to call a nonexistent constructor for the WordCloud data member, hence the compiler error.
Marking the WordCloud member static masks but does not fix this problem because static data members are not initialized in constrictors. That's why your code was able to compile with the modification.
To fix this problem, provide a constructor for your FontTestingApp class that uses the member initialization list to call an appropriate constructor for the WordCloud data member.
You must not make the wc member static.
You must instead call the constructor for your class explicitely from the FontTestingApp constructor's initialization list, like this:
FontTestingApp::FontTestingApp(): wc(&wordList) {
// more initialization
}
精彩评论