Can't pass string literal to constructor

Started by
12 comments, last by Bregma 10 years, 4 months ago

I thought I had understood it. But now this site is confusing me... http://www.informit.com/articles/article.aspx?p=1852519

Class Member Initialization

C++11 pulls another rabbit out of its hat with class member initializers. Perhaps an example will best illustrate these:


class C
{
int x=7; //class member initializer
public:
C();
};

The data member x is automatically initialized to 7 in every instance of class C. In former dialects of C++, you would use the more cumbersome mem-init notation for the same purpose:


class C
{
int x;
public:
C() : x(7) {}
};

(...)

Notice that a class member initializer can consist of any valid initialization expression, whether that's the traditional equal sign, a pair of parentheses, or the new brace-init:


class C
{
string s("abc");
double d=0;
char * p {nullptr};
int y[5] {1,2,3,4};
public:
C();
};

Regardless of the initialization form used, the compiler conceptually transforms every class member initializer into a corresponding mem-init. Thus, class C above is semantically equivalent to the following class:


class C2
{
string s;
double d;
char * p;
int y[5];
public:
C() : s("abc"), d(0.0), p(nullptr), y{1,2,3,4} {}
};

class C
{
int x=7; //class member initializer

The way I understood it, this shouldn't be a class member initializer. It should be an assignment instead....

And how can these two be similar? That's exactly what I was trying in the first place!



class C
{
string s("abc");

C() : s("abc")
Advertisement

Extended support for this kind of initialization was introduced with C++11, so if you're not using C++11 then you cannot do that and you have to use the initializer list. But even if you do use a compiler that claims C++11 support, you may only have partial C++11 support. Visual Studio up to 2012 for example, without the very latest test patches at least, does not support this.

As far as my quick tests show, and I am not able to look into the language specification right now, you can only initialize with the assignment operator so your multi-parameter constructor call appears to be invalid anyway.

In C++11, if you have it enabled, and if your compiler supports it, it'd look like this:


Button bSstart = Button("StartGame",   50, 20, 50, 5);
//OR:
Button bSstart = {"StartGame",   50, 20, 50, 5};
//OR:
Button bSstart{"StartGame",   50, 20, 50, 5};
 
//But not:
Button bSstart("StartGame",   50, 20, 50, 5); //<--- Syntax error

(I compiled a quick snippet to be sure)

The middle version (blah = {...}) can cause confusion if your constructor takes a std::initializer_list as a single parameter, like the standard library containers do.

So a class can take an assignment like this:

class Foo
{
private:
int bar = 0;
};

No, that class definition has an inline initializer, not an assignment statement. An inline initializer is allowed by the 1997 standard only for integral values although some compilers allow it as an extension for floating-point values as well.

But no initializations can happen outside the class initializer itself. Member initializations must happen in the class initialization too. Hence only this is valid:

class Foo
{
public:
Foo() : bar(0) {}

private:
int bar;
}

No, that's an initializer list in the constructor, and yes it's valid but no more so than the inline initializer, at least for integral values.

class Foo
{
private:
int bar = 0;
/* This ALWAYS works as an assignment operator, never as an initializer, even if no initializer is
* provided for this member in the class initializer list / body. */
};

That is an incorrect assumption. It's never an assignment, it's always an initialization.

If I'm thinking wrong just tell me, please.

Yes.

Just stick to initializer lists, you can't go wrong. Well, mostly.

Stephen M. Webb
Professional Free Software Developer

This topic is closed to new replies.

Advertisement