- A constructor is specified by a method name that is the same as the class name.
- Never has a return type
- May or may not have parameters.
default constructor
无参调用的构造函数为默认构造函数,可以是没有参数,或是所有的参数都有默认值。
什么时候需要默认构造函数?
- 对象数组。
SimpleClass arr[3]; SimpleClass* cls = new SimpleClass[10];
- 首先会为所有的对象分配连续的内存空间;
- 然后调用每个对象的默认构造函数。如果
SimpleClass
未定义默认构造函数,会编译不过。
- 往标准库的容器存储对象时也需要默认构造函数;
- 在其他类中的对象成员初始化时。
如何创建构造函数
如果没有声明任何构造函数,编译器会帮你创建一个无参的默认构造函数。但是如果你声明了默认构造函数或是其他构造函数,编译器不再为你生成默认的构造函数。
显示地指定默认构造函数。
class SimpleClass {
public:
SimpleClass() = default;
SimpleClass(double value);
}
在不需要任何构造函数,也不需要编译器生成默认构造函数时,可以显示地移除构造函数。
class SimpleClass {
public:
SimpleClass() = delete;
}
构造函数初始化
class SimpleClass {
public:
SimpleClass(double val);
void setValue(double val) {
mValue = val;
}
private:
double mValue;
}
// 方法1
SimpleClass::SimpleClass(double val) {
setValue(val);
}
// 方法2,使用constructor initializer
SimpleClass::SimpleClass(double val): mValue(val)
{
}
When C++ creates an object, it must create all the date members of the object before calling the constructor.
As part of creating these data members, it must call a constructor on any of them that are themselves objects. By the time you assign a value to an object inside you constructor body, you are not actually constructing that object.
You are only modifying its value.
A ctor-initializer allows you to provide initial values for data members as they are created, which is more efficient than assigning values to them later.
Several data types must be initialized in a ctor-initializer or with an in-class initializer
- const data members. You cannot legally assign a value to a const variable after it is created. Any value must be supplied at the time of creation.
- Reference data members. References cannot exist without referring to something.
- Object data members for which there is no default constructor. C++ attempts to initialize member objects using a default constructor. If no default constructor exists, it cannot initialize the object.
- Base classes without default constructors. TODO: Chapter 10.
- TODO: Chapter 10
class Foo
{
public:
Foo(double value);
private:
double mValue;
};
Foo::Foo(double value) : mValue(value)
{
cout << "Foo::mValue = " << mValue << endl;
}
class MyClass
{
public:
MyClass(double value);
private:
double mValue; // 注意顺序
Foo mFoo; // 注意顺序
};
MyClass::MyClass(double value) : mValue(value), mFoo(mValue)
{
cout << "MyCalss::mValue = " << mValue << endl;
}
// 初始化对象
MyClass instance(1.2);
// Out put
Foo::mValue = 1.2
MyClass::mValue = 1.2
// 调整下 mValue 和 mFoo的顺序
// Out put
Foo::mValue = -9.25596e+61
MyClass::mValue = 1.2
The data members are initialized in the order they appear in the definition of the class, not the order in the ctor-initializer!
Copy Constructor
It allows you to create an object that is an exact copy of another object.
If you donnot write a copy constructor, C++ generates one for you.
When the Copy Constructor Is Called
The default semantics for passing arguments to functions in C++ is pass-by-value.
- Whenever you pass an object to a function or method, the compiler calls the copy constructor of the new object to initialize it.
void printString(std::string inString) { cout<< inString <<endl; } void printStringView(std::string_view sv) { cout << sv << endl; }
std::string
is actually a class, not a built-in type, when you make a call toprintString
passing astd::string
argument, the parameter inString is initialized with a call to its copy constructor. When theprintString()
method finishes, inString is destroyed.std::string_view
is also a class, but basically just a pointer and a length, so it is very cheap to copy, and is usually passed by value.
- When returning objects by value from a function, the copy constructor might also get called.
For performance reasons, it is best to pass objects by const reference instead of value.
可以显示 指定或删除copy constructor.
SimpleClass(const SimpleClass& src) = default;
// or
SimpleClass(const SimpleClass& src) = delete;
Initializer-list Constructors
An initializer-list constructor is a constructor with an
std::initializer_list<T>
as first parameter, without any additional parameters or with additional parameters having default values.
You need to include the <initializer_list>
header.
class EvenSequence
{
public:
EvenSequence(initializer_list<double> args)
{
if (args.size() % 2 != 0) {
throw invalid_argument("initializer_list should contain even number of elements.");
}
mSequence.assign(args);
}
private:
vector<double> mSequence;
};
// Example
EvenSequence p1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
The Standard Library has full support for initializer-list constructors
. For example:
// with initializer-list constructors
std::vector<std::string> v = {"string 1", "string 2", "string 3"};
// without initializer-list constructors
std::vector<std::string> v;
v.push_back("string 1");
v.push_back("string 2");
v.push_back("string 3");
Delegating Constructor
Delegating constructors allow constructors to call another constructor from the same class.
- this call cannot be placed in the constructor body;
- It must be in the
ctor-initializer
; - It must be the only
member-initializer
in the list;
Make sure you avoid constructor recursion while using delegate constructor.
class MyClass
{
MyClass(char c) : MyClass(1.2) { }
MyClass(double d) : MyClass('m') { }
};
Move Constructor
- Chapter 9