600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++

Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++

时间:2022-05-15 21:45:41

相关推荐

Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++

Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)

条款05:了解C++默默编写并调用哪些函数编译器为类生成的默认函数做了什么?总结

《Effective C++》是一本轻薄短小的高密度的“专家经验积累”。本系列就是对Effective C++进行通读:

条款05:了解C++默默编写并调用哪些函数

什么时候 empty class(空类)不再是个空类呢?

;如果class没有定义构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数,那么C++内部会动创建一个默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数。并且这些函数默认都是public且inline的。见条款30

示例:

如果你写下一个空类:

class Empty{}; //空类

这就好比,你写下了:

class Empty{public:Empty() {... }//default构造函数Empty(const Empty& rhs) {... } //Copy构造函数~Empty() {... } //析构函数Empty& operator={const Empty& rhs) {... } //copy assignment操作符};

只有当这些函数被需要(被调用),它们才会被编译创建。

class Empty{}; //空类Empty e1; //调用e1的默认构造函数Empty e2(e1);//调用e2的默认拷贝构造函数e2 = e1;//调用e2的默认拷贝赋值运算符//程序结束//调用e1与e2的默认析构函数

编译器为类生成的默认函数做了什么?

现在知道编译器为你写了函数,那么这些函数做了什么呢?

默认构造函数与默认析构函数

默认构造函数与默认析构函数主要是给编译器一个地方用来防止“隐藏幕后”的代码,像是调用基类和非静态成员变量的构造函数和析构函数

注意:编译器定义的默认析构函数是非virtual的,除非这个class的基类自身有virtual析构函数(这种情况下这个函数的虚属性(virtual)来自于基类)

默认拷贝构造函数和默认拷贝赋值运算符

默认拷贝构造函数和默认拷贝赋值运算符一样,都是在拷贝/对象赋值时将类的每一个非静态成员变量逐个拷贝到目标对象之中。

示例:

template<typename T>class NamedObject{public:NamedObject(const char* name, const T& value);NamedObject(const std::string& name, const T& value);...private:std::string name;T objectValue;};

这里声明了一个构造函数,所以编译器不再为它创建默认构造函数。而NamedObject即没有声明拷贝构造函数,也没有声明拷贝赋值运算符,所以编译器会生成默认的。下面是拷贝构造函数的用法:

NamedObject<int> no1("dongshao", 2);NamedObject<int> no2(no1); //调用NamedObject<int>的默认拷贝构造函数

上面的no2对象调用默认的拷贝构造函数来拷贝no1对象,其中的操作有:

将no1对象的name数据成员拷贝给no对象的name数据成员(又因为name为string类型,所以最终会调用string的拷贝构造函数来拷贝name)

因为此程序中模板类型为int,所以objectValue为int内置类型,直接将no1对象的objectValue赋值给no2的objectValue

对于赋值运算符来说,其与拷贝构造函数一样,也是逐个将数据成员进行重新赋值。

拷贝赋值运算符的错误注意事项

虽然拷贝构造函数与拷贝赋值运算符用起来比较类似,但是有一种情况会导致出错,如:

template<typename T>class NamedObject{public://以下构造函数不再接受一个 const 名称,因为 nameValue//因为name变为了string引用类型,因此参数1位char*类型的构造函数就没有用了NamedObject(std::string& name, const T& value);...//假设并未声明 operator=private:std::string& name;//string的引用类型const T objectValue; // const};std::string newDog("Persephone");std::string oldDog("Satch");NamedObject<int> p(newDog, 2);NamedObject<int> s(oldDog,36);p = s; //错误

上述“p=s”错误的原因:

name:因为name为引用类型了,我们知道引用一旦绑定就不可以改变引用指向,但是在此处拷贝赋值运算符中,我们将p的name引用从一开始指向于newDog又指向了oldDog,因此会发生错误。

objectValue:因为objectValue为const类型,因此在初始化之后其值就不可以改变了,此处将p的值从2改变为36因此会发生错误。

面对这个难题,C++ 的响应是拒绝编译那一行赋值动作。如果你打算在一个"内含引用成员"的 class 内支持赋值操作,你必须定义自己的拷贝赋值操作符。

在某些情况下,使用了系统提供的默认拷贝赋值运算符会出现错误。因此有些情况下我们不希望使用class提供的默认拷贝赋值运算符,那么就需要提供一种方法:

如果一个基类将拷贝赋值运算符声明为private,那么编译器就拒绝为派生类生成默认的拷贝赋值运算符。因为基类如果想使用这些函数,那么这些函数会相应的处理基类成份,但是基类是private的,所以不可以使用。

这种方法不仅适用于拷贝赋值运算符,对于构造函数、拷贝构造函数都同样有效

NOTE:

编译器可以暗自为class创建 default 构造、 copy 构造、copy 赋值操作符,以及析构函数。

总结

期待大家和我交流,留言或者私信,一起学习,一起进步!

Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。