您的位置:首页 > 游戏 > 手游 > 展厅设计制作_天津制作网站的公司电话_网上推广用什么平台推广最好_磁力宝最佳搜索引擎入口

展厅设计制作_天津制作网站的公司电话_网上推广用什么平台推广最好_磁力宝最佳搜索引擎入口

2024/10/5 22:21:32 来源:https://blog.csdn.net/weixin_71738303/article/details/142373619  浏览:    关键词:展厅设计制作_天津制作网站的公司电话_网上推广用什么平台推广最好_磁力宝最佳搜索引擎入口
展厅设计制作_天津制作网站的公司电话_网上推广用什么平台推广最好_磁力宝最佳搜索引擎入口

8、初始化器列表构造函数

        初始化器列表构造函数是一个带有std::initializer_list<T>作为第一个参数并且 没有任何其他参数或者有另外参数但是有缺省值的构造函数。initializer_list<T>类模板在<initializer_list>中定义。下面的类演示了其用法。该类只接收一个带有偶数个元素的initializer_list<double>;否则就抛出例外。

class EvenSequence
{
public:EvenSequence(initializer_list<double> values){if (values.size() % 2 != 0) {throw invalid_argument{ "initializer_list should ""contain even number of elements." };}m_sequence.reserve(values.size());for (const auto& value : values) {m_sequence.push_back(value);}// Or:// m_sequence.assign(values);}void print() const{for (const auto& value : m_sequence) {std::print("{}, ", value);}println("");}
private:vector<double> m_sequence;
};

        在初始化器构造函数中可以使用基于范围的for循环来访问初始化器列表的元素,使用size()成员函数获得初始化器列表的元素数量。

        EvenSequence初始化器列表构造函数使用基于范围的for循环从给定的initializer_list<T>中拷贝元素。也可以使用vector的assign()成员函数。vector的不同的成员函数,包括assign(),我们会在以后详细讨论,作为简单的介绍,只是给出vector的一个概况,下面是使用assign()的初始化器列表构造函数的例子:

EvenSequence(initializer_list<double> values)
{if (values.size() % 2 != 0) {throw invalid_argument{ "initializer_list should ""contain even number of elements." };}m_sequence.assign(values);
}

EvenSequence对象可以构造如下:

	try {EvenSequence p1{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };p1.print();EvenSequence p2 { 1.0, 2.0, 3.0 };} catch (const invalid_argument& e) {println("{}", e.what());}

        p2的构造会抛出例外,因为在初始化器列表中含有奇数个元素。

        标准库有对初始化器列表构造函数的全部支持。例如,std::vector容器可以用初始化器列表进行初始化:

vector<string> myVec { "String 1", "String 2", "String 3" };

        如果没有初始化器列表构造函数,初始化这个vector的一个方法就是使用push_back()调用:

vector<string> myVec;
myVec.push_back("String 1");
myVec.push_back("String 2");
myVec.push_back("String 3");

        初始化器列表不限于构造函数,也可以用于正常的函数。

        注意:当类不仅拥有初始化器列表构造函数,还具有另一个单个参数的构造函数时,就要注意去调用正确的那一个了。例如,std::vector有初始化器列表构造函数来初始化一个带有给定元素集的vector。它也具有一个可以接收一个单独参数的构造函数,想要大小的新的vector。调用初始化器列表构造函数是使用大括号的初始化器,{},而调用另外的单独参数的构造函数是使用括号,()。例如:

vector<int> v1 { 6 }; // Constructs a vector with a single element, 6.
vector<int> v2 ( 6 ); // Constructs a vector with 6 default-
// initialized elements.

9、代理构造函数

        代理构造函数允许构造函数调用同一个类中的另一个构造函数。然而,该调用不能放到构造函数体内;一定要在构造函数初始化器中,必须是列表中唯一的成员初始化器。如下示例:

SpreadsheetCell::SpreadsheetCell(string_view initialValue)
: SpreadsheetCell { stringToDouble(initialValue) }
{
}

        当string_view构造函数(代理构造函数)被调用时,首先代理调用目标构造函数,本例中为参数为double的构造函数。当目标构造函数返回时,代理构造函数体被执行。

        在使用代理构造函数时,要确信避免出现构造函数递归,下面是一个例子:

class MyClass
{MyClass(char c) : MyClass { 1.2 } { }MyClass(double d) : MyClass { 'm' } { }
};

        第一个构造函数代理向第二个构造函数,而第二个又代理回第一个。这种代码的行为没有定义,依赖于编译器,会出现完全不可预知的结果。

10、构造函数转化与显式构造函数

        目前SpreadsheetCell的构造函数集如下:

export class SpreadsheetCell
{
public:SpreadsheetCell() = default;SpreadsheetCell(double initialValue);SpreadsheetCell(std::string_view initialValue);SpreadsheetCell(const SpreadsheetCell& src);// Remainder omitted for brevity
};

        单个参数的double与string_view构造函数可以用于将double或者string_view的对象转化为SpreadsheetCell。这样的构造函数叫做转化构造函数。编译器可以用这样的构造函数来执行隐式地转化。示例如下:

SpreadsheetCell myCell { 4 };
myCell = 5;
myCell = "6"sv; // A string_view literal

        其行为可能不总是你想要的。可以阻止编译器进行这样的转化,要通过标志构造函数为explicit。explicit关键字只在类定义中出现,示例如下:

export class SpreadsheetCell
{
public:SpreadsheetCell() = default;SpreadsheetCell(double initialValue);explicit SpreadsheetCell(std::string_view initialValue);SpreadsheetCell(const SpreadsheetCell& src);// Remainder omitted for brevity
};

        这样改了之后,下面这一行就不会编译成功:

myCell = "6"sv; // A string_view literal (see Chapter 2).

        在c++11之前,转化构造函数可以只有一个参数,如SpreadsheetCell例子中所示。从c++11开始,因为支持了列表初始化,转化构造函数可以有多个参数。我们看一个例子。假设你有如下的类:

class MyClass
{
public:MyClass(int) { }MyClass(int, int) { }
};

        这个类有两个构造函数,从c++11开始,都是转化构造函数。下面的例子展示了编译器自动转化像1,{1}与{1,2}这样的参数为使用转化构造函数的MyClass的实例:

void process(const MyClass& c) { }
int main()
{process(1);process({ 1 });process({ 1, 2 });
}

        为了阻止这样的隐式转化,两个都可以被标记为explicit:

class MyClass
{
public:explicit MyClass(int) { }explicit MyClass(int, int) { }
};

        这样修改之后,就要显式地执行这些转化了;示例如下:

process(MyClass{ 1 });
process(MyClass{ 1, 2 });

        将一个布尔型的参数显式地转化为一个判断explicit是可能的。语法如下:

explicit(true) MyClass(int);

        当然了,explicit(true)与explicit是等价的,但是对于使用类型特征的通用模板代码的上下文中就会变得很有用。对于类型特征,可以人家一起给定类型的特定属性,比如一个特定类型是否可以转化为另一个类型。这样的类型特征的结果可以用于explicit()的参数。类型特征允许书写高级的通用代码,这个我们以后再讨论吧。

        注意:推荐标注至少任一个构造函数可以用一个单个参数的explicit调用,以避免隐式转化。如果真的有隐式转化的使用情况,可以将构造函数标记为explicit(false),这样做的目的就是告诉用户你的类就是隐式转化的,是被明明白白允许的。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com