【C++】C++的构造函数
构造函数是特殊的成员函数,只要创建类类型的对象,都要执行构造函数。构造函数的工作是保证每个对象的数据成员具有合适的初始值。
class Sales_Item {
public:
//operations on Sales_item objects
//default constructor needed to initialize members of built-in type
Sales_item(): units_sold(), revenue(0.0){}
private:
std::string isbn;
unsigned units_solds;
double revenue;
};
构造函数的名字与类的名字相同,并且不能指定返回类型。像其他任何函数一样,它们可以没有形参,也可以定义多个形参。
构造函数的几个特性:
1. 构造函数可以重载
2. 构造函数不能声明为const
class Sales_item {
public:
Sales_item() const; //error
};
constg构造函数是不必要的。创建类类型的const对象时,运行一个普通构造函数来初始化该const对象。构造函数的工作是初始化对象。不管对象是否为const,都用一个构造函数初始化该对象。
构造函数初始化式:
Sales_item::Sales_item(const string &book):
isbn(book), units_sold(), revenue(0.0) {}
构造函数初始化列表以一个冒号开始,接着是一个逗号分隔的数据成员列表,每个数据成员后面跟一个放在圆括号里中的初始化式。这个构造函数将isbn成员初始化为book形参的值,将units_sold和revenue初始化为0。与任意的成员函数一样,构造函数可以定义在类的内部或外部。构造函数初始化式只在构造函数的定义中而不在声明中指定。
构造函数初始化列表难以理解的一个原因在于,省略初始化列表并在构造函数的函数体内对数据成员赋值是合法的。例如,可以将接受一个string的Sales_item构造函数编写为:
//legal but sloppier way to write constructor
// no constructor initializer
Sales_item::Sales_item(const string &book) {
isbn = book;
units_sold = ;
revenue = 0.0;
}
这个构造函数给类Sales_item的成员赋值,但没有进行显式初始化。不管有没有显式的初始化式,在执行构造函数之前,要初始化化isbn成员。这个构造函数隐式使用默认的string构造函数初始化isbn。执行构造函数的函数体时,isbn已经有值了。该值被构造函数函数体中的赋值所覆盖。
从概念上讲,可以认为构造函数分两个阶段:(1)初始化阶段;(2)普通的计算阶段
不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化(调用默认构造函数,若没有默认构造函数,则编译错误)。初始化发生在计算阶段开始前。
构造函数初始化列表中没有显式提及的每个成员,使用与初始化变量相同的规则进行初始化:
1)类类型:运行该类型的默认构造函数
2)内置或复合类型的成员的初始值依赖于对象的作用域;在局部作用域中这些成员不被初始化,而在全局作用域中它们初始化为0;
因为内置类型的成员不进行隐式初始化,所以对这些成员是进行初始化还是赋值似乎无关紧要。但对于类类型的数据成员若未在初始化列表当中显式初始化,而是在函数体里赋值,则相当于先调用类的默认构造函数初始化,再在函数体里赋值,故相比于直接利用初始化列表,效率较低。
如果没有为类提供初始化式,则编译器会隐式地使用成员类型的默认构造函数,如果那个类没有默认构造函数,则编译器尝试使用默认构造函数失败。
必须利用初始化列表的几种情况:
1)没有默认构造函数的类类型的成员;
2)const类型的成员;
3)引用类型的成员;
上述类型必须在初始化列表中进行初始化,在函数体中对他们赋值是不起作用的。
1 class ConstRef {
2 public:
3 ConstRef(int ii)'
4 private:
5 int i;
6 const int ci;
7 int &ri;
8 };
9 //no explicit constructor: error ri is uninitialized
10 ConstRef::Constef(int ii)
11 {
12 i = ii; //ok
13 ci = ii; //error:cannot assign to a const;
14 ri = i; //assignes to ri which was not bound to an objects
15 } 可以初始化const对象或引用类型的对象,但不能对它们赋值。在开始开始执行构造函数的函数体之前,要完成初始化。初始化const或引用类型数据成员唯一的机会是在构造函数初始化列表中。
成员初始化的次序:
每个成员在初始化列表中只能指定一次。
成员被初始化的顺序就是成员定义的次序,而与他们在构造函数的初始化列表中的顺序无关。
默认构造函数:
只要定义一个对象时没有提供初始化式,就使用默认构造函数。为所有形参提供默认实参的构造函数也定义了默认构造函数。
一个类哪怕只定义一个构造函数(包括复制构造函数),编译器也不会再生成默认构造函数。只有当一个类没有定义默认构造函数,编译器才自动生成一个。
如果类包含内置或复合类型(数组)的成员,则该类不依赖于合成的默认构造函数。它应该定义自己的默认构造函数。
合成的默认构造函数使用与变量初始化相同的规则来初始化成员。此外,每个构造函数应该为每个内置或复合类型的成员提供初始化式。没有初始化内置或复合类型成员的构造函数,将使那些成员处于未定义状态。除了作为赋值的目标外,以任何方式使用一个为定义的成员都是错误的。
使用默认构造函数:
Sales_item myobj();
编译myobj的声明没有问题,然而,使用myobj时会出错。原因是myobj的定义被编译器解释为一个函数的声明。使用默认构造函数定义一个对象的正确方式是去掉最后的空括号:
Sales_item myobj;
下面的代码也是正确的:
Sales_item myobj = Sales_item();
在这里,我们创建并初始化一个Sales_item对象,然后用它来按值初始化myobj。编译器通过运行Sales_item的默认构造函数来按值初始化一个Sales_item。
没有默认构造函数的后果:
假设有一个NoDefaultl,它没有定义自己的默认构造函数,却有一个接受一个string实参的构造函数。因为该类定义了一个构造函数,因此编译器将不会合成默认构造函数。NoDefault没有默认构造函数,一位置:
1)具有Nodefault成员的每个类的每个构造函数,必须传递一个初始的string值给Default构造函数来显式地初始化NoDefault成员。
2)编译器将不会为具有NoDefault类型成员的类合成默认构造函数。如果这样的类希望提供默认构造函数,就必须显式地定义,并且默认构造函数必须显式地初始化其Nodefault成员。
3)NoDefault类型不能用作动态分配数组的元素。如果没有为类类型数组提供初始化式,则将用默认构造函数初始化每个元素。
4)NoDefault类型的静态分配数组必须为每个元素提供一个显式的初始化。
5)如果有一个保存NoDefault对象的容器,例如vector,就不能使用接受容器大小而没有同时提供一个元素初始化的构造函数。编译器首先调用默认构造函数创建
一个临时值来初始化,然后使用复制构造函数复制到容器的每个元素。
即以下都是错误的:
NoDefault nd;
NoDefault nd[];
NoDefault *pa = new A[];
std::vector<NoDefault> vec();
下面哪些陈述不正确:
a)类必须提供至少一个构造函数
不正确。因为类也可以不提供构造函数,这时使用由编译器合成的默认构造函数。
b)默认构造函数的形参列表中没有形参。
不正确。因为为所有形参都提供了默认实参的构造函数也定义了默认构造函数,而这样的构造函数形参列表中是有形参的。
c)如果一个类没有有意义的默认值,则该类不应该提供默认构造函数
不正确。因为如果一个类没有默认构造函数(指的是该类提供了构造函数,但没有提供自己的默认构造函数),则在编译器需要隐式使用默认构造函数的环境中,该类就不能使用,所以,一个类定义了其他构造函数,则通常也应该提供一个默认构造函数。
d)如果一个类没有定义默认构造函数,则编译器会自动生成一个,同时将每个数据成员初始化为相关类型的默认值。
不正确。因为编译器合成的默认构造函数,不是将每个数据成员初始化行为相关类型的默认值,而是使用与变量初始化相同的规则来初始化成员;类类型的成员执行各自的默认构造函数进行初始化;内置和复合类型的成员,只对定义在全局作用域中的对象才初始化。
【C++】C++的构造函数的更多相关文章
- .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...
- javascript工厂模式和构造函数模式创建对象
一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...
- JS继承之借用构造函数继承和组合继承
根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...
- PHP与JAVA构造函数的区别
早期的PHP是没有面向对象功能的,但是随着PHP发展,从PHP4开始,也加入了面向对象.PHP的面向对象语法是从JAVA演化而来,很多地方类似,但是又发展出自己的特色.以构造函数来说,PHP4中与类同 ...
- C++ 拷贝构造函数和赋值运算符
本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...
- golang语言构造函数
1.构造函数定义 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- Aop动态生成代理类时支持带参数构造函数
一.背景 在某些情况下,我们需要植入AOP代码的类并没有默认构造函数.那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数.自己折腾了1晚上没搞定,现在搞定了发出来供大家一起 ...
- C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?
Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...
- Android中自定义样式与View的构造函数中的第三个参数defStyle的意义
零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...
随机推荐
- 20155203 2016-2017-3 《Java程序设计》第三周学习总结
20155203 2016-2017-3 <Java程序设计>第三周学习总结 教材知识要点总结 第四章 文档主文档名必须与公开类名称相同.一个原始码中可以定义多个类,但是只能有一个公开类. ...
- 20155233 2016-2017-2 《Java程序设计》第1周学习总结
20155233 2016-2017-2 <Java程序设计>第1周学习总结 教材学习内容总结 本周主要学习教材的第一章.第二章,了解了Java的发展历程,最基本的Java环境的搭建,以及 ...
- JUC——线程同步锁(锁处理机制简介)
锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...
- hadoop 基础入门
启动: 格式化节点:bin/hdfs namenode -format 全部启动:sbin/start-dfs:datanode.namenode sbi ...
- idea下增加scala
1 idea工具下,下载scala插件 2 idea下新建scala工程 File——New——module 如果按照上图,设置后点击下载,出现下图下载过慢情况下, 这里我选择了等待,大概等了半小时才 ...
- sqoop安装与简单实用
一,sqoop安装 1.解压源码包 2.配置环境变量 3.在bin目录下的 /bin/configsqoop 注释掉check报错信息 4.配置conf目录下 /conf/sqoop-env.sh 配 ...
- 关于购买Redis服务器:腾讯云、阿里云还是华为云?
个人分类: redis使用 编辑 新年伊始,很多商家都开始进行新年产品大促销,在分布是缓存Redis领域,几家大公司也是打得如火如荼,各有千秋啊. 现在市场上比较有口碑的商家有腾讯云.阿里云.华为云三 ...
- PHP性能优化 -理论篇
什么情况下,遇到了PHP性能问题? 1 PHP语法使用的不恰当 2 使用PHP语言做不了它不擅长做的事 3 用php语言连接的服务不给力 4 PHP自身的短板 5 我也不 ...
- java引用Arcface,实现人脸识别(demo)
## 开发环境准备: ###开发使用到的软件和工具: * Jdk8.mysql5.7.libarcsoft_face.dll(so).libarcsoft_face_engine.dll(so).li ...
- cs231n学习笔记(一)计算机视觉及其发展史
在网易云课堂上学习计算机视觉经典课程cs231n,觉得有必要做个笔记,因为自己的记性比较差,留待以后查看. 每一堂课都对应一个学习笔记,下面就开始第一堂课. 这堂课主要是回顾了计算机视觉的起源及其后来 ...