3

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?

timrau
  • 22,578
  • 4
  • 51
  • 64
hetepeperfan
  • 4,292
  • 1
  • 29
  • 47
  • What do you mean when you say "I receive a compiler error because I never intended the Data::setValue() to be virtual"? The compiler error has to do with the value in the union, so it's not clear what your intent for the virtualness of setValue() has to do with it. – Chad Jul 10 '15 at 14:39
  • @chad The compiler error disappears when I declare `virtual void Data::setValues(int, int)` as `void Data::setValues(int, int)` There is some significant difference there, that is my question. – hetepeperfan Jul 10 '15 at 14:44
  • 1
    In case the answers below don't satisfy you, here's a more pragmatic approach: Think about the 'vtable' pointer that is part of many implementations. This pointer gets set during construction, which makes the according object unsuitable for storage in a union, because only objects that don't require any kind of initialisation during construction can be placed on top of each other. – Ulrich Eckhardt Jul 10 '15 at 15:14

5 Answers5

3

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

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.

Community
  • 1
  • 1
Tyler
  • 197
  • 3
  • 13
1

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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

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".

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
1

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.

Wojtek Surowka
  • 20,535
  • 4
  • 44
  • 51
  • C++ does not have structures (or "structs" for short). Only classes. Classes may be defined using the `struct` keyword but this is only for compatibility and doesn't make them "structs". (I find this a much more effective way of explaining to C programmers how this stuff works in C++.) For what it's worth, this wasn't always the case: before 1987 or so, C++ had both classes and structures, with structures working as they do in C. – Lightness Races in Orbit Jul 10 '15 at 14:56