非静态成员初始化
在编写具有多个构造函数的类(大多数构造函数)时,必须为每个构造函数中的所有成员指定默认值会导致冗余代码。如果更新成员的默认值,则需要触摸每个构造函数。
从C ++ 11开始,可以直接为普通类成员变量(不使用static关键字的变量)提供默认初始化值:
class Rectangle
{
private:
double m_length = 1.0; // m_length 的默认值是1.0
double m_width = 1.0; // m_width 的默认值是1.0
public:
Rectangle()
{
//此构造函数将使用上面的默认值,因为它们不会在此处重写
}
void print()
{
std::cout << "length: " << m_length << ", width: " << m_width << '\n';
}
};
int main()
{
Rectangle x; // x.m_length = 1.0, x.m_width = 1.0
x.print();
return 0;
}
该程序产生结果:
length:1.0,width: 1.0
非静态成员初始化(也称为类内成员初始值设定项)为构造函数将提供的成员变量提供默认值,如果构造函数不为成员本身提供初始化值(通过成员初始化列表)。
但是,注意构造函数仍然确定可以创建哪种对象。考虑以下情况:
class Rectangle
{
private:
double m_length = 1.0;
double m_width = 1.0;
public:
//注意: 这个例子不提供默认构造函数
Rectangle(double length, double width)
: m_length(length), m_width(width)
{
// m_length 和m_width 通过构造函数被初始化 (默认值就不用啦!)
}
void print()
{
std::cout << "length: " << m_length << ", width: " << m_width << '\n';
}
};
int main()
{
Rectangle x; // 即使成员具有默认初始化值,也不会编译,因为不存在默认构造函数
return 0;
}
即使我们为所有成员提供了默认值,也没有提供默认构造函数,因此我们无法创建没有参数的Rectangle对象。
如果提供了默认初始化值并且构造函数通过成员初始值设定项列表初始化成员,则成员初始值设定项列表将优先。以下示例显示了这一点:
class Rectangle
{
private:
double m_length = 1.0;
double m_width = 1.0;
public:
Rectangle(double length, double width)
: m_length(length), m_width(width)
{
// m_length 和m_width 通过构造函数被初始化 (默认值就不用啦!)
}
void print()
{
std::cout << "length: " << m_length << ", width: " << m_width << '\n';
}
};
int main()
{
Rectangle x(2.0, 3.0);
x.print();
return 0;
}
这打印:
length:2.0,width:3.0
请注意,使用非静态成员初始化初始化成员需要使用等号或大括号(统一)初始化程序 - 直接初始化表单在此处不起作用。
规则:支持使用非静态成员初始化为您的成员变量提供默认值。
Quiz time
1)更新以下程序以使用非静态成员初始化和成员初始化列表。
2)为什么我们需要在上面的程序中声明一个空的默认构造函数,因为所有成员都是通过非静态成员初始化初始化的?
#include <string>
#include <iostream>
class Ball
{
private:
std::string m_color;
double m_radius;
public:
//没有任何默认参数的构造函数
Ball()
{
m_color = "black";
m_radius = 10.0;
}
// 构造函数仅仅有color参数 (radius采用默认值)
Ball(const std::string &color)
{
m_color = color;
m_radius = 10.0;
}
// 构造函数仅仅有radius参数 (color采用默认值)
Ball(double radius)
{
m_color = "black";
m_radius = radius;
}
// 具有color和radius参数的构造函数
Ball(const std::string &color, double radius)
{
m_color = color;
m_radius = radius;
}
void print()
{
std::cout << "color: " << m_color << ", radius: " << m_radius << '\n';
}
};
int main()
{
Ball def;
def.print();
Ball blue("blue");
blue.print();
Ball twenty(20.0);
twenty.print();
Ball blueTwenty("blue", 20.0);
blueTwenty.print();
return 0;
}
该程序应该产生结果:
color:black,radius:10
color:blue,radius:10
color:black,radius:20
color:blue,radius:20
解决方案:
#include<iostream>
#include<string>
using namespace std;
class Ball
{
public:
//默认构造函数不提供任何参数,每一个参数都采用默认值
Ball()
{
}
//m_radius采用默认参数,这里仅仅提供m_color参数
Ball(const string &color) :m_color(color)
{
}
//m_color采用默认参数,这里仅仅提供m_radius参数
Ball(double radius) :m_radius(radius)
{
}
//这里提供m_radius和m_color参数
Ball(const string &color, double radius) :m_color(color), m_radius(radius)
{
}
void print();
private:
string m_color="black";
double m_radius = 10;
};
void Ball::print()
{
cout << "颜色:" << m_color << ",半径" << m_radius << endl;
}
int main()
{
Ball def;
def.print();
Ball blue("blue");
blue.print();
Ball twenty(20.0);
twenty.print();
Ball blueTwenty("blue", 20.0);
blueTwenty.print();
return 0;
}
问题2:为什么我们需要在上面的程序中声明一个空的默认构造函数,因为所有成员都是通过非静态成员初始化初始化的?
回答:“Ball def;”将寻找一个默认构造函数来处理对象的实例化。如果该默认构造函数不存在(即使它是空的),编译器将抛出错误。