持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
- 当我们使用一个类对象去初始化一个对象时,编译器会自动创建一个构造函数,这个构造函数被称为复制构造函数,因为它创建对象的一个副本。
-
- 因此当我们在自定义的构造函数中进行某些操作,但是我们使用赋值的方法生成一个新的对象,那么这个新的对象在生成的时候就只会执行复制构造函数而不执行我们定义的构造函数,这样就会造成一些严重的错误,这样的错误归根结底在于编译器的自动创建构造函数。
- C++自动提供下面这些成员函数
-
- 默认构造函数,如果没有定义
- 默认析构函数,如果没有定义
- 复制构造函数,如果没有定义
- 赋值运算符,如果没有定义
- 地址运算符,如果没有定义
-
如果将一个对象赋给另一个对象,编译器将会提供隐式的复制构造函数和隐式的赋值运算符的定义
这篇文章我们先来讨论默认构造函数和复制构造函数
编译器提供的成员函数
默认构造函数
- 构造函数是用来初始化定义的成员数据的,如果没有定义构造函数,编译器会生成一个默认的构造函数例如:
-
- Lunck ::Lunck() {};
- 这个默认的构造函数什么都没做,因此它的值在初始化的时候是未知的。
- 如果定义了构造函数,那么编译器就不会自动生成默认构造函数,如果希望创建对象的时候不显示的初始化那么可以自定义默认构造函数,这种构造函数没有任何参数,但是可以初始化数据成员的值。
- 有参数的构造函数也可以是默认的构造函数,只要给他设定默认值即可,例如:
-
- Lunck(int n=10) { lunck_t = n;}
- 只能有一个默认的构造函数,否则会造成冲突:例如
Lunck() {lunck_t = 10;};
Lunck(int n=10) { lunck_t = n;}
// 如果在创建对象的时候这样定义
Lunck t();
// 在这种情况下,t跟上面两种默认构造函数都能匹配,就会造成编译器的错误
复制构造函数
- 复制构造函数是用于将一个对象复制到新创建的对象中,它是用于初始化的过程(包括按值传递参数),而不是常规的赋值过程。
- 复制构造函数的原型如下,通常它会要求传入一个类对象常量的引用作为参数。 例如:
class_name(const class_name &)
- 我们需要做的事就是知道这个函数何时被调用以及它有什么作用
何时调用复制构造函数
- 将一个新对象初始化为一个现有的同类对象
- 一下这几种情况都会触发复制构造函数
// Stringbad 是一个类
// tiddo 是一个Stringbad对象
Stringbad ditto(tiddo)
Stringbad also = tiddo
Stringbad gotty = Stringbad(tiddo)
Stringbad *pt = new Stringbad(tiddo)
以上这四种情况都会调用复制构造函数,只是实现的情况可能会有些不同
-
注:每当函数按值传递对象或者函数返回对象的时候都会使用复制构造函数,传值意味着会创建原始变量的一个副本,当我们创建对象的副本时就会调用复制构造函数
-
因此我们应该尽量避免按值传递,而使用按引用传递,这样既避免了复制构造函数的调用,也节省了空间
默认复制构造函数的功能
- 当我们使用函数的值传递从而触发了复制构造函数的时候,复制构造函数的作用就是将现有对象的非静态变量值(成员复制也称为浅复制,仅仅就是值)逐个的复制给新创建的对象。例如:(因为对象的数据成员不能被直接访问,因此下面的代码不能通过编译)。
Stringbad sport = tiddo 相当于
sport.name = tiddo.name
sport.age = tiddo.name
- 静态变量不被复制的原因在于,静态变量属于整个类而不是各个对象。
因此我们能意识到复制构造函数带来某些错误,那么我们该如何避免呢,下一篇文章我们来介绍。