I am asked how many members there are in the following class:
class xClass {
private:
int u;
double w;
public:
void func();
void print() const;
xClass();
xClass(int a, double b);
};
i only see 6, but the solution says 9?
This is for C++ 11.
§ 9.2 Class members:
Members of a class are data members, member functions (9.3), ...
§ 12 Special member functions:
The default constructor (12.1), copy constructor and copy assignment operator (12.8), move constructor and move assignment operator (12.8), and destructor (12.4) are special member functions. [Note: The implementation will implicitly declare these member functions ...]
This hints at the fact that special member functions are indeed member functions (unlike the tasmanian tiger, which is not a tiger) and therefore class members in the sense of 9.2.
An implicitly-declared special member function is declared at the closing } of the class-specifier.
This means, special member functions are not added to the class at a later stage (e.g. during compilation); they're there once the class has been defined. Also, special member functions are declared even if they are not used.
To summarize: in C++ 11, there are 11 members. In C++ 03, move constructor and move assignment operator do not exist, so there might be 9 members. However, I did not check the wording for C++ 03, so there might be 6 members.
I read the comments but I have to say that it is difficult to say how many class members in your example. I think that there are some contradictions in the C++ Standard description. For example in section 9.2 Class members there is said
1 The member-specification in a class definition declares the full set
of members of the class; no member can be added elsewhere.
So if to follow the Standard in your example there are indeed only 6 members because only they take part in the member-specification.
Also according to the C++ Standard
Members of a class are data members, member functions (9.3),...
If to look through section 9.3 then we will see that constructors, destructors and copy and move assignment operators are not mentioned there.:) They are called special member functions. But special member functions are not mentioned among member functions.
So you can say bravely that there are only 6 class members. If somebody have questions then let he ask the C++ Standard Committee.:)
Related
In a C++ project that is full of objects (with proper behaviors) and relatively few of non-object-oriented structs (consisting of only data fields and no methods), I would like to prevent the accidental misuse of these structs, in which one might try to create a class inheriting from it.
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
This seems to make a good use case for the C++11 "final" keyword, which marks a class or struct as non-inheritable.
However, I wonder if the "final" keyword causes the struct to become non-POD?
I suspect that the standards documentation may have addressed this issue, but I am not intelligent enough to sift through the very long documentations to find out. Any useful pointers would be welcome.
Note: I am not interested in merely knowing that it passes the compilation of some compiler vendors. Passing compilation do not guarantee:
Whether the compiled code will execute correctly in all situations (especially when the technique is applied in a larger, more complex project),
Whether the C++ standards body intends this to be used in this way.
#include <iostream>
using namespace std;
struct Pod final
{
int a;
int b;
int c;
};
#if 0
class FailsBecauseCannotDeriveFromFinalAnything : public Pod
{
};
#endif
class ContainsSomethingFinalAsMember
{
public:
ContainsSomethingFinalAsMember() : pod() {}
private:
Pod pod;
};
int main()
{
std::cout << std::is_pod < Pod > :: value << std::endl;
return 0;
}
According to my understanding, because these "POD" (plain old data) structs do not have a virtual destructor, it is not possible to properly delete a derived class object (if one is allowed to create it) via a pointer of the POD type.
It's not possible given a raw pointer, but it is possible given a smart pointer object, such as std::shared_ptr or a std::unique_ptr with an appropriate deleter.
Since smart pointers were standardized, there are few excuses to continue following the poor practice of using the delete operator manually. Certainly, classes shouldn't be designed around compatibility with the delete operator. Each class interface should be designed with its particular uses in mind.
No, it's not a good practice to make every class either final or polymorphic.
However, I wonder if the "final" keyword causes the struct to become non-POD?
No, it's still POD. The requirements for POD are standard layout (in turn requiring no base class, no access specifiers between members, no virtual anything) and trivial special member functions (copy/move constructor, assignment operator, destructor).
However, the purpose of POD-ness is to allow you to use memcpy instead of properly constructing objects, which good C++ code would avoid doing.
Marking a class final does not change its POD status. Quoting C++11:
9 [class]:
6 A trivially copyable class is a class that:
has no non-trivial copy constructors (12.8),
has no non-trivial move constructors (12.8),
has no non-trivial copy assignment operators (13.5.3, 12.8),
has no non-trivial move assignment operators (13.5.3, 12.8), and
has a trivial destructor (12.4).
A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable.
[ Note: In particular, a trivially copyable or trivial class does not have virtual functions or virtual base
classes.—end note ]
7 A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with
non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
8 A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class. ...
10 A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no
non-static data members of type non-POD struct, non-POD union (or array of such types). ...
12.1 [class.ctor]
5 ... A default constructor is trivial if it is not user-provided and if:
its class has no virtual functions (10.3) and no virtual base classes (10.1), and
no non-static data member of its class has a brace-or-equal-initializer, and
all the direct base classes of its class have trivial default constructors, and
for all the non-static data members of its class that are of class type (or array thereof), each such class
has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
12.4 [class.dtor]
5 ... A destructor is trivial if it is not user-provided and if:
the destructor is not virtual,
all of the direct base classes of its class have trivial destructors, and
for all of the non-static data members of its class that are of class type (or array thereof), each such
class has a trivial destructor.
Otherwise, the destructor is non-trivial.
12.8 [class.copy]
12 A copy/move constructor for class X is trivial if it is not user-provided and if
— class X has no virtual functions (10.3) and no virtual base classes (10.1), and
— the constructor selected to copy/move each direct base class subobject is trivial, and
— for each non-static data member of X that is of class type (or array thereof), the constructor selected
to copy/move that member is trivial;
otherwise the copy/move constructor is non-trivial.
25 A copy/move assignment operator for class X is trivial if it is not user-provided and if
class X has no virtual functions (10.3) and no virtual base classes (10.1), and
the assignment operator selected to copy/move each direct base class subobject is trivial, and
for each non-static data member of X that is of class type (or array thereof), the assignment operator
selected to copy/move that member is trivial;
otherwise the copy/move assignment operator is non-trivial.
As you see, the definition of a POD struct does not take into account whether the class has the class-virt-specifier final.
I am working on an application which in my opinion is rather poorly designed but that's another issue. There is a simple class in that app that I need to add a variable to. In this case I would like to add a STL stack to the class. Should be simple except that elsewhere the same class is used within a union and the compiler then complains that the class has a copy constructor. If I remove my added variable it compiles fine. My first thought was to add the stack as a pointer and then initialise it in the constructor but then the compiler complains that the class has a non trivial constructor.
My second (not ideal) thought was to add it as a pointer and initialise it outside the class. I know this isn't a good solution but I am up against some poorly designed code here which I cannot rewrite. However, this won't work because where I would need to initialise it, I cannot know if it has already been initialised or not. I cannot initialise the pointer in the class to NULL as even just doing that makes the compiler complain that the class now has a non-trivial constructor.
I guess my question is two-fold. Is there a way of adding a STL stack to a class that is used in a union? If not, is there a way of initialising a pointer to NULL in a class that is used in a union?
The class and union look something like this:
class MyClass
{
public:
std::stack<short> Index; // ideally what I wanted
}
union
{
int nNum;
MyClass myclass;
} u;
Please note: I cannot change the union. I accept that I cannot do what I was thinking. Is there any alternative no matter how silly it might sound. I cannot change the union or redesign the app as much as I would like to. This is the problem when you work on large apps that were first written around 18 years ago.
You could define the union as
union
{
int nNum;
MyClass * myclass;
} u;
This has the added benefit that int and pointer are the same size and it compiles.
Also, your example won't compile. It's missing ';' at the end of the class.
The answer for both questions is NO for C++03.
Since
9.5 Unions [class.union]
1
...
An object of a class with a non-trivial default constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor
can an array of such objects. If a union contains a static data member, or a member of reference type,
the program is ill-formed.
You still can add constructor to the union that will init pointer instead of class ctor.
In C++11 however you can provide your own constructors for union, that should implement correct way to copy classes with non trivial constructors.
9.5 Unions [class.union]
2 A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non-static data member of reference type the program is ill-formed. At most one non-static data member of a union may have a brace-or-equal-initializer. [Note: If any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be
user-provided or it will be implicitly deleted (8.4.3) for the union. — end note ]
You may also be interested in a following article
http://cpp11standard.blogspot.com/2012/11/c11-standard-explained-1-unrestricted.html
consider the following code:
class A
{
friend class B;
friend class C;
};
class B: virtual private A
{
};
class C: private B
{
};
int main()
{
C x; //OK default constructor generated by compiler
C y = x; //compiler error: copy-constructor unavailable in C
y = x; //compiler error: assignment operator unavailable in C
}
The MSVC9.0 (the C++ compiler of Visual Studio 2008) does generate the default constructor but is unable to generate copy and assignment operators for C although C is a friend of A. Is this the expected behavior or is this a Microsoft bug? I think the latter is the case, and if I am right, can anyone point to an article/forum/... where this issue is discussed or where microsoft has reacted to this bug. Thank you in advance.
P.S. Incidentally, if BOTH private inheritances are changed to protected, everything works
P.P.S. I need a proof, that the above code is legal OR illegal. It was indeed intended that a class with a virtual private base could not be derived from, as I understand. But they seem to have missed the friend part. So... here it goes, my first bounty :)
The way I interpret the Standard, the sample code is well-formed. (And yes, the friend declarations make a big difference from the thing #Steve Townsend quoted.)
11.2p1: If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.
11.2p4: A member m is accessible when named in class N if
m as a member of N is public, or
m as a member of N is private, and the reference occurs in a member or friend of class N, or
m as a member of N is protected, and the reference occurs in a member or friend of class N, or in a member or friend of a class P derived from N, where m as a member of P is private or protected, or
there exists a base class B of N that is accessible at the point of reference, and m is accessible when named in class B.
11.4p1: A friend of a class is a function or class that is not a member of the class but is permitted to use the private and protected member names from the class.
There are no statements in Clause 11 (Member access control) which imply that a friend of a class ever has fewer access permissions than the class which befriended it. Note that "accessible" is only defined in the context of a specific class. Although we sometimes talk about a member or base class being "accessible" or "inaccessible" in general, it would be more accurate to talk about whether it is "accessible in all contexts" or "accessible in all classes" (as is the case when only public is used).
Now for the parts which describe checks on access control in automatically defined methods.
12.1p7: An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body. If that user-written default constructor would be ill-formed, the program is ill-formed.
12.6.2p6: All sub-objects representing virtual base classes are initialized by the constructor of the most derived class (1.8). If the constructor of the most derived class does not specify a mem-initializer for a virtual base class V, then V's default constructor is called to initialize the virtual base class subobject. If V does not have an accessible default constructor, the initialization is ill-formed.
12.4p5: An implicitly-declared destructor is implicitly defined when it is used to destroy an object of its class type (3.7). A program is ill-formed if the class for which a destructor is implicitly defined has:
a non-static data member of class type (or array thereof) with an inaccessible destructor, or
a base class with an inaccessible destructor.
12.8p7: An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type. [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2).] A program is ill-formed if the class for which a copy constructor is implicitly defined has:
a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
a base class with an inaccessible or ambiguous copy constructor.
12.8p12: A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:
a nonstatic data member of const type, or
a nonstatic data member of reference type, or
a nonstatic data member of class type (or array thereof) with an inaccessible copy assignment operator, or
a base class with an inaccessible copy assignment operator.
All these requirements mentioning "inaccessible" or "accessible" must be interpreted in the context of some class, and the only class that makes sense is the one for which a member function is implicitly defined.
In the original example, class A implicitly has public default constructor, destructor, copy constructor, and copy assignment operator. By 11.2p4, since class C is a friend of class A, all those members are accessible when named in class C. Therefore, access checks on those members of class A do not cause the implicit definitions of class C's default constructor, destructor, copy constructor, or copy assignment operator to be ill-formed.
Your code compiles fine with Comeau Online, and also with MinGW g++ 4.4.1.
I'm mentioning that just an "authority argument".
From a standards POV access is orthogonal to virtual inheritance. The only problem with virtual inheritance is that it's the most derived class that initializes the virtually-derived-from class further up the inheritance chain (or "as if"). In your case the most derived class has the required access to do that, and so the code should compile.
MSVC also has some other problems with virtual inheritance.
So, yes,
the code is valid, and
it's an MSVC compiler bug.
FYI, that bug is still present in MSVC 10.0. I found a bug report about a similar bug, confirmed by Microsoft. However, with just some cursory googling I couldn't find this particular bug.
Classes with virtual private base should not be derived from, per this at the C++ SWG. The compiler is doing the right thing (up to a point). The issue is not with the visibility of A from C, it's that C should not be allowed to be instantiated at all, implying that the bug is in the first (default) construction rather than the other lines.
Can a class with a private virtual base class be derived from?
Section: 11.2 [class.access.base]
Status: NAD Submitter: Jason
Merrill Date: unknown
class Foo { public: Foo() {} ~Foo() {} };
class A : virtual private Foo { public: A() {} ~A() {} };
class Bar : public A { public: Bar() {} ~Bar() {} };
~Bar() calls
~Foo(), which is ill-formed due to
access violation, right? (Bar's
constructor has the same problem since
it needs to call Foo's constructor.)
There seems to be some disagreement
among compilers. Sun, IBM and g++
reject the testcase, EDG and HP accept
it. Perhaps this case should be
clarified by a note in the draft. In
short, it looks like a class with a
virtual private base can't be derived
from.
Rationale: This is what was intended.
btw the Visual C++ v10 compiler behaviour is the same as noted in the question. Removing virtual from the inheritance of A in B fixes the problem.
class Foo {
Foo(int val) { /* Do some initialization */ }
Foo() { /* Do nothing */ }
};
union Bar {
Foo foo;
};
That code generates this error:
error C2620: member 'Bar::foo' of union 'Bar' has user-defined constructor or non-trivial default constructor
I understand why you'd throw that error if the constructor actually did something, but the constructor here takes no parameters and does nothing. Is there any way I can stuff this class into a union? I've had to resort all the way to doing char foo[sizeof(Foo)] and would like a cleaner solution.
Originally from this question:
Initializing a union with a non-trivial constructor:
From C++03, 9.5 Unions, pg 162
A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class.An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects
So, your class is forbidden to be a member of the union.
This isn't allowed in the C++03 standard.
If objects with user defined default constructors were allowed in a union, the compiler couldn't decide which constructor to use, because all refer to the same memory location. Thus, objects with user defined constructors aren't allowed in unions.
The compiler will ignore the fact that your constructor doesn't do anything, because it might be defined elsewhere than the union.
You might get away with a C++0x constructor() = default;
Standard-specialists will likely answer this question more precisely than I do, but if I recall correctly, union members must be of POD type.
Use boost::variant if you want to use non-POD classes inside a union.
If your class has a user defined constructor, destructor or copy constructor, or assignment operator then it cannot be inside of a Union.
take two following classes:
class Test1{
public:
Test1()=default;
Test1(char in1,char in2):char1(in1),char2(in2){}
char char1;
char char2;
};
class Test2{
public:
Test2()=default;
Test2(char in1,char in2):char1(in1),char2(in2){}
private:
char char1;
char char2;
};
I know in c++0x both of these classes are considered as POD types and we can initialize objects of them using initializer lists as below:
Test1 obj1={'a','b'};//valid in c++0x
Test2 obj2={'a','b'};//valid in c++0x
But I wonder what the technical reason is that when we have different access specifiers in a class like below, it's not possible to use initializer list for initializing objects of that class and that class is not considered as a POD type ?
class Test{
public:
Test()=default;
Test(char in1,char in2):char1(in1),char2(in2){}
char char1;
private:
char char2;
};
Test obj={'a','b'};//invalid in c++0x
In case you don't know definition of PODs in c++0x:
A class/struct is considered a POD if it is trivial, standard-layout, and if all of its non-static members are PODs.
A trivial class or struct is defined as one that:
Has a trivial default constructor. This may use the default constructor syntax (SomeConstructor() = default;).
Has a trivial copy constructor, which may use the default syntax.
Has a trivial copy assignment operator, which may use the default syntax.
Has a trivial destructor, which must not be virtual.
A standard-layout class or struct is defined as one that:
Has only non-static data members that are of standard-layout type
Has the same access control (public, private, protected) for all non-static members
Has no virtual functions
Has no virtual base classes
Has only base classes that are of standard-layout type
Has no base classes of the same type as the first defined non-static member
Either has no base classes with non-static members, or has no non-static data members in the most derived class and at most one base class with non-static members. In essence, there may be only one class in this class's hierarchy that has non-static members.
In case you don't know what a trivial constructor or operator is:
Compiler generates a trivial one of each of following items for a class, in case it isn't user-declared:
Copy constructor, destructor and copy assignment operator.
And also if there's no user-declared constructor for a class, a trivial default constructor is generated for that class, in case there are any user-declared constructors you can use the syntax(SomeConstructor() = default;) to make your own trivial default constructor.
The "technical" reason is due to the following:
Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (C++0x §9.2/12).
So long as all the nonstatic data members have the same access control, their order is well-specified; otherwise their order is unspecified.
class Test{
public:
Test()=default;
Test(char in1,char in2):char1(in1),char2(in2){}
char char1;
private:
char char2;
};
considering above class following syntax is valid in c++0x:
Test obj={'a','b'};//valid in c++0x
The final proposal is here.