- Overview
-
Table of Contents
-
Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Constructors
- Constructors FAQ, Part I
- Constructors FAQ, Part II
- Constructors FAQ, Part III
- C++0x Constructor-Related Features FAQ, Part I
- C++0x Constructor-Related Features FAQ, Part II
- C++0x Constructor-Related Features FAQ, Part III
- Assignment Operator
- Copy Constructor and Assignment Operator FAQ, Part I
- Copy Constructor and Assignment Operator FAQ, Part II
- Destructors
- Destructors FAQ
- Summary
- Online Resources
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
-
Special Member Functions: Constructors, Destructors, and the Assignment Operator
Constructors FAQ, Part II
Last updated Jan 1, 2003.
The second installment lists the conditions under which an implicitly-declared constructor will also be implicitly-defined. It also explains why the compiler implicitly declares constructors even when they are not defined, seemingly for no purpose.
Question: When Does the Compiler Implicitly-Define An Implicitly-Declared Constructor?
Answer: An implicitly-declared default constructor is implicitly-defined if and only if the implementation needs that definition. The implementation needs an implicit definition in the following cases:
Classes with virtual member functions. A class that has virtual member functions must have a non-trivial constructor. A non-trivial constructor is either a user-defined constructor or a constructor that is implicitly defined. The non-trivial constructor is responsible for internal initializations such as assigning the correct vptr address of each polymorphic object.
Base and embedded subobjects. A class must have a non-trivial constructor if it has base class(es) with non-trivial constructor(s) or embedded objects with non-trivial constructor(s). The non-trivial constructor has to initialize the base class(es) and the embedded object(s) first. For example:
struct T
{
T() {cout<<"hello"<<endl;} //user-defined constructor
};
struct U:T
{
//default ctor implicitly defined
};
The compiler implicitly-defines a default constructor for U. U’s constructor invokes the non-trivial constructor of the base class T whenever you instantiate an object of type U:
U u; //implicitly defined ctor invokes T::T() first.
Virtual inheritance. The presence of a virtual base class necessitates a non-trivial constructor to ensure that only one virtual subobject is present in every derived object. Therefore, if a class has any virtual base class(es), its constructor must be non-trivial.
Question: Why Does The Compiler Implicitly Declare Trivial Constructors If They Are Never Defined?
Answer: Under certain conditions, the compiler implicitly-declares a default constructor but doesn’t define it. Such a constructor is said to be trivial. Many C++ programmers find this notion of trivial member functions rather confusing. Why on earth does the compiler bother to declare a member function implicitly when it knows that that function won’t be implicitly defined? Do implicit declarations of this kind serve any purpose?
The first thing to bear in mind is that implicit declarations (and implicit definitions) are conceptual. That is, the compiler doesn’t go through your header files and inserts lines of code with constructor declarations to them. Rather, the compiler, the linker and the program behave as if the trivial member functions were declared. In practice, the compiler simply sets a few bits in a class’ type information record, indicating that the said type has a (trivial) default constructor declaration. So if you’re worried about excess verbiage of source files or the potential bloat of executable files, rest assured that nothing of this kind should happen.
Now let’s get to the more important conundrum: why bother at all with these trivial declarations? After all, C doesn’t need this mechanism for its structs and unions. The truth is that implicit declarations have a contractual role. Each implicit declaration is like an article in a contract that states how a certain class may be used. When the compiler implicitly declares one of the special member functions, it grants certain authorizations to the user. By contrast, if the compiler doesn’t implicitly-declare a member function, the user is restricted with respect the class’s usage. Consider:
struct Blocked
{
public:
Blocked(const Blocked&);
};
By now you know that an explicit declaration of a copy-constructor precludes the implicit declaration of a default constructor. Since the default constructor is neither implicitly nor explicitly declared, you can’t instantiate objects of class Blocked:
Blokced b; //error, no default constructor available Blocked *p = new Blocked; //error
Without the implicit declarations mechanism, programmers would have to go through every class and struct, manually adding declarations of every member function that’s needed for instantiating, copy-constructing, assigning and destroying objects. The following POD type demonstrates this:
struct Date
{
int day, month, year;
};
The compiler implicitly declares the following member functions for Date:
- A trivial default constructor
- A trivial copy constructor
- A trivial assignment operator
- A trivial destructor
These implicit declarations enable you to use Date as follows:
Date d; //implicit declaration of default ctor and dtor allow this Date * pdate= new Date; //same here Date d2(d); //implicit copy ctor declaration allows this *pdate=d2; //implicit assignment operator declaration allows this delete pdate; //implicit dtor declaration allows this
The trivial member functions play an important role in C++ programming. To realize how much time and drudgery they save, try to circumvent their implicit declaration by adding explicit declarations to the class:
struct Date
{
int day, month, year;
private:
~Date(); //declared but not defined
Date(const Date&); //ditto
};
Now the following code no longer compiles:
Date d; //error, no default ctor Date * pdate= new Date; //same error here Date d2(d); //error, no accessible copy ctor
Coming Next
The next installment will answer the following questions and explain the rationale behind the answers: does an implicitly-defined constructor allocate memory for its object? Does an implicitly-defined constructor initialize user-declared data members?
