Reputation: 4411
In the following fragment of code I receive a compiler error when the method Data::setValue(int, int) is declared virtual:
struct Data{
int ma;
int mb;
virtual void setValues(int a, int b){
ma = a;
mb = b;
}
};
struct ThreadMessage {
enum type {
DATA
};
type msg_type;
union content {
Data d;
int a;
}content;
};
The error that the compiler (g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3) gives me is:
struct.cpp:19:14: error: member 'Data ThreadMessage::content::d' with constructor not allowed in union
struct.cpp:19:14: error: member 'Data ThreadMessage::content::d' with copy assignment operator not allowed in union
This set of compiler errors took me completely off guard. In the actual code, I had many more attributes and functions. Therefore, I started looking where I put the bloody operator=() and constructor but I didn't write them in struct Data
.
I know my problem disappears when I make the Data::setValues as not virtual. But why does the struct Data have a constructor? When exactly does a struct have a constructor in C++? And why does the compilation error disappear when I make virtual void Data::setValues(int, int)
non virtual?
Upvotes: 3
Views: 3185
Reputation: 320401
The compiler error message is a bit misleading. From the conceptual language point of view your class Data
will have a constructor in any case, regardless of whether the function is virtual or not.
The compiler is apparently a pre-C++11 one (or works in pre-C++11 mode). And it does not like the fact that Data
's constructor is non-trivial. It is specifically the non-triviality of Data
's constructor that makes the compiler to say that Data
is a class "with constructor".
In this particular case the constructor becomes non-trivial once you introduce at least one virtual function into the class.
A non-trivial constructor is a constructor that has to do something (in your case - initialize the per-object household information that support polymorphism). I.e. it is a constructor that must exist physically in generated code. Meanwhile a trivial constructor exists only conceptually, but produces no code. The compiler is referring to that physical distinction when it separates classes into ones "with constructor" and ones "without constructor".
Upvotes: 1
Reputation: 20993
The error messages you quoted are misleading, so no doubt you wonder why making the function non-virtual fixes the problem.
First - structs and classes in C++ have constructors and copy assignment operators. If you do not create them yourself, they will be created for you. (You may delete those default versions). In your example there is an automatically generated constructor of Data
, and also automatically generated assignment operator.
Now why the error messages are misleading? Because they are not true. In C++ you can have union members with constructors or assignment operators. The problem starts when those member functions are not trivial. Before C++11 it was just not possible to have an union member with non-trivial constructor. C++11 changed it, but still without writing additional functions it is not possible to use such union.
A struct/class with virtual functions has non-trivial member functions as constructor and assignment operator (because hidden data member needs to be managed). This is why when you make the function non-virtual the errors disappear - then the member functions become trivial and your struct may be used as a union member without problems.
Upvotes: 1
Reputation: 385114
When exactly does a struct have a constructor in c++
Always.
The error message is a bit confusing, but it's saying that you cannot have a class there.
A class is a type defined with either the struct
keyword or the class
keyword.
Every class has a constructor and an assignment operator, whether it's user-provided or not.
Upvotes: 1
Reputation: 197
You may want to browse through this thread: Struct Constructor in C++?
The Reader's Digest version is that, like classes, structs have a default constructor, which you can overload and define however you like.
Upvotes: 2
Reputation: 234665
Barring the default access of members, a struct
and a class
are identical in C++.
Unless you program carefully (and have C++11), you cannot have a class
or a struct
member in a union
since there would be ambiguity as to how such members of the union should be constructed.
That's what your compiler is telling you.
Upvotes: 3