views:

123

answers:

7

I always thought, that there are only two defaults construcors: constructor with no arguments, and copy construtor.

But today I wrote something like this:

First I wanted to make sure that in C++ initialization of structures in c-style is still valid..

struct Foo{
    int a;
    bool b;
    char* c;
    double d;
};
//..
Foo arr[2]={{0, true, "a", 3.14}, {1, false, "z", 42.0}};

ok, this works. But next, I decided to check what will happen after changing struct to class.

class Bar{
 public:
    int a;
    bool b;
    char* c;
    double d;
};

//..

Bar arr[2]={{0, true, "a", 3.14}, {1, false, "z", 42.0}};//works
Bar bar;                                                 //works
Bar bar2=arr[1];                                         //works
//Bar bar3(2, false, "so", 7.0);                         //of course doesn't work
//first, second, third ways works... 

this is compilable as long as class Bar doesn't have any private/protected fields (but it can contains methods). So, as long as compiler can create class which uses only simple features of structures, so long this can be compiled.

  • First question: Am I right?

  • Second question: Is it compiler's (gcc in this case) feature or this is exactly what Standard says?

[EDIT]:

code //Bar bar3(2, false, "so", 7.0); //of course doesn't work is not an issue here ;)

+9  A: 

I decided to check what will happen after changing struct to class.

The only difference between struct and class is default visibility of members and default inheritance mode. struct D : B { ... is equivalent to class D : public B { public: ....

FredOverflow
A: 

Bar meets the POD type requirements, which means it can be initialized like a C structure. Being a class or a struct has no impact on this.

Etienne de Martel
Very close, but not quite. Bar is a "aggregate" type. I don't recall off hand if the requirements for aggregate are stronger or weaker than POD, but I'm thinking stronger. Only aggregate types can be initialized with the {...} syntax.
Noah Roberts
Hm, interesting. Didn't know that.
Etienne de Martel
+3  A: 

Well it seems normal that "//Bar bar3(2, false, "so", 7.0);" doesn't work since you didn't define a constructor with that signature. In order for that to work you need to define a constructor with that signature in your class. The compiler only generates the default constructor and default copy constructor for you unless you declare them yourself.

__dominic
+2  A: 

With //Bar bar3(2, false, "so", 7.0); you are calling a ctor that does not exist.

slashmais
A: 

I always thought, that there are only two defaults construcors: constructor with no arguments, and copy construtor.

1.Yes - you are right about the above.

2.

Is it compiler's (gcc in this case) feature

What 'feature' are you talking about? Just overload your constructor to have a method Bar::Bar(int,bool,char*,double) and you're smooth sailing

Marm0t
A: 

It is well know that default constructor and default copy constructor exist for any class in C++ regardless if they are explicitly declared or not. I think what is happening when you use the following syntax:

Bar arr[2]={{0, true, "a", 3.14}, {1, false, "z", 42.0}}; 

Is that the compiler inferred the type of objects then call the default constructor of each object, then assign each field conformed its position in the class definition. The compiler does not could call the default copy constructor because no object of the same type is passed directly when you create the new object, this is, copy constructor should be called in the following scenarios:

Bar a;     //default constructor is called
Bar b(a);  //default copy constructor is called
Bar c = a; //default copy constructor is called

What you should do is to add the default constructors to the Bar class and then debug for knowing what really is happening...

ArceBrito
"...regardless if they are explicitly declared or not." - this is not true. If construcor with for examle 1 parameter is given, then default constructor is not generated. And I don't have to add anything, because I don't need copy constructor here ;) Besides.. I think here none constructor is called at all, because this class is treated like structure.
noisy
@noisy: actually default constructor is only implicitly generated by the compiler if there is no user-declared constructor. What I mean is that you should add a default constructor and a copy constructor to your class then debug, and notice what really is happening with your class. Also different compilers behave different. I don't have gcc compiler so I can't run the test at this moment...
ArceBrito
+2  A: 

Although you called it C-style initialization, its official name is initializer list. Only aggregates can be initialized with initializer lists (see 8.5 in the standard).

An aggregate is an array or a class with

  • no user-declared constructors,
  • no private or protected non-static data members,
  • no base classes,
  • and no virtual functions.

Those are the actual restrictions you have. That means you may use initializer lists with non-POD aggregates:

struct Aggregate
{
   std::string s;
};

Aggregate ag = { "hello" };
Tamas Demjen