C++类构造函数、拷贝构造函数、复制构造函数、复制构造函数、构造函数显示调用和隐式调用
一、 构造函数是干什么的
- class Counter
- {
- public:
- // 类Counter的构造函数
- // 特点:以类名作为函数名,无返回类型
- Counter()
- {
- m_value = 0;
- }
- private:
- // 数据成员
- int m_value;
- }
该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作
eg: Counter c1;
编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象c1的m_value值设置为0
故:构造函数的作用:初始化对象的数据成员。
二、 构造函数的种类
- class Complex
- {
- private :
- double m_real;
- double m_imag;
- public:
- Complex() //一般构造函数
- {
- m_real = 0.0;
- m_imag = 0.0;
- }
- Complex(double real, double imag) //一般构造函数
- {
- m_real = real;
- m_imag = imag;
- }
- Complex(const Complex & c) //拷贝构造函数
- {
- // 将对象c中的数据成员值复制过来
- m_real = c.m_real;
- m_imag = c.m_imag;
- }
- Complex &operator=( const Complex &rhs ) //赋值构造函数
- {
- // 首先检测等号右边的是否就是左边的对象本身,若是本对象本身,则直接返回
- if ( this == &rhs )
- {
- return *this;
- }
- // 复制等号右边的成员到左边的对象中
- this->m_real = rhs.m_real;
- this->m_imag = rhs.m_imag;
- // 把等号左边的对象再次传出
- return *this;
- }
- };
// 无参数构造函数
// 如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做
// 只要你写了一个下面的某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来
// 一般构造函数(也称重载构造函数)
// 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)
// 例如:你还可以写一个 Complex( int num)的构造函数出来
// 创建对象时根据传入的参数不同调用不同的构造函数
// 复制构造函数(也称为拷贝构造函数)
// 复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中
// 若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询 有关 “浅拷贝” 、“深拷贝”的文章论述
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象,
//需要注意的一点是,这个其实就是一般的构造函数,但是对于出现这种单参数的构造函数,C++会默认将参数对应的类型转换为该类类型,有时候这种隐私的转换是我们所不想要的,所以需要使用explicit来限制这种转换。
// 赋值构造函数
// 注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建
// 若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作
下面使用上面定义的类对象来说明各个构造函数的用法:
int main()
{
// 调用了无参构造函数,数据成员初值被赋为0.0
Complex c1,c2;
// 调用一般构造函数,数据成员初值被赋为指定值
Complex c3(1.0,2.5);
// 也可以使用下面的形式
Complex c3 = Complex(1.0,2.5);
// 把c3的数据成员的值赋值给c1
// 由于c1已经事先被创建,故此处不会调用任何构造函数
// 只会调用 = 号运算符重载函数
c1 = c3;
// 调用拷贝构造函数( 有下面两种调用方式)
Complex c5(c2);
Complex c4 = c2; // 注意和 = 运算符重载区分,这里等号左边的对象不是事先已经创建,故需要调用拷贝构造函数,参数为c2
//这一点特别重要,这儿是初始化,不是赋值。其实这儿就涉及了C++中的两种初始化的方式:复制初始化和赋值初始化。其中c5采用的是复制初始化,而c4采用的是赋值初始化,这两种方式都是要调用拷贝构造函数的。
}
三、深拷贝与浅拷贝
如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针 时则会导致两次重复delete而出错。下面是示例:
- #include <iostream.h>
- #include <string.h>
- class Person
- {
- public :
- // 构造函数
- Person(char * pN)
- {
- m_pName = new char[strlen(pN) + 1];
- //在堆中开辟一个内存块存放pN所指的字符串
- if(m_pName != NULL)
- {
- //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
- strcpy(m_pName ,pN);
- }
- }
- // 系统创建的默认复制构造函数,只做位模式拷贝
- Person(Person & p)
- {
- //使两个字符串指针指向同一地址位置
- m_pName = p.m_pName;
- }
- ~Person( )
- {
- delete m_pName;
- }
- private :
- char * m_pName;
- };
- void main( )
- {
- Person man("lujun");
- Person woman(man);
- // 结果导致 man 和 woman 的指针都指向了同一个地址
- // 函数结束析构时
- // 同一个地址被delete两次
- }
// 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
Person(Person & chs);
{
// 用运算符new为新对象的指针数据成员分配空间
m_pName=new char[strlen(p.m_pName)+ 1];
if(m_pName)
{
// 复制内容
strcpy(m_pName ,chs.m_pName);
}
// 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
}
四、构造函数显示调用和隐式调用
C/C++中的显示调用和隐式调用:
(1)显示调用
显示调用是指在程序中能找到相应的调用代码,或者说是手动调用的
(2)隐式调用
隐式调用是指程序中找不到相应的调用代码,或者说是编译器自动调用的
类的构造函数与析构函数一般就是隐式调用的。
如下代码:
- A()
- {
- //一般构造函数
- }
- A& operator =(const A& a)
- {
- // 赋值构造函数
- }
- A(const A& a)
- {
- //拷贝构造函数
- }
- ~A()
- {
- }
下面给出一些构造示例:
- void f()
- {
- // A()构造函数被调用
- A a;
- // A(const A& a)构造函数被调用
- A b(a);
- // A(const A& a)构造函数被调用
- A c = a;
- // A& operator = (const A& a)赋值操作符重载函数被调用
- b = c;
- }
- // 离开f()函数之前,a,b,c的析构函数被调用,做一些清理工作
注意上面 "A c = a" ,这句代码实际调用的是拷贝构造函数,而非赋值函数。属于构造函数的隐式调用,可以使用explicit修饰构造函数的定义,使得其不能被隐式调用,如下:
- explicit A(int n)
- {
- m_data = NULL;
- if (n>0)
- m_data = new int[n];
- }
C++类构造函数、拷贝构造函数、复制构造函数、复制构造函数、构造函数显示调用和隐式调用的更多相关文章
- C++转换构造函数和隐式转换函数 ~ 转载
原文地址: C++转换构造函数和隐式转换函数 用转换构造函数可以将一个指定类型的数据转换为类的对象.但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个Complex类对象转换成doubl ...
- C++ 隐式类类型转换
<C++ Primer>中提到: “可以用 单个形参来调用 的构造函数定义了从 形参类型 到 该类类型 的一个隐式转换.” 这里应该注意的是, “可以用单个形参进行调用” 并不是指构造函数 ...
- C++ 隐式类类型转换和转换操作符
隐式类类型转换 C++语言定义了内置类型之间的几个自动转换.也可以定义如何将其他类型的对象隐式转换为我们的类类型,或将我们的类类型的对象隐式转换为其他类型.为了定义到类类型的隐式转换,需要定义合适的构 ...
- C++隐式类类型转化
隐式类类型转换:可以用 单个形参来调用 的构造函数定义了从 形参类型 到 该类类型 的一个隐式转换 class Person { public: Person(): mName()name, mAge ...
- [C++]复制构造函数、赋值操作符与隐式类类型转换
问题:现有类A定义如下: class A{public: A(int a) //构造函数 { ...
- C++构造函数 & 拷贝构造函数 & 派生类的构造函数 & 虚继承的构造函数
构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数 ...
- C++编写字符串类CNString,该类有默认构造函数、类的拷贝函数、类的析构函数及运算符重载
编码实现字符串类CNString,该类有默认构造函数.类的拷贝函数.类的析构函数及运算符重载,需实现以下“=”运算符.“+”运算.“[]”运算符.“<”运算符及“>”运算符及“==”运算符 ...
- C++类中拷贝构造函数详解
a. C++标准中提到"The default constructor, copy constructor and copy assignment operator, and destruc ...
- C++ //构造函数调用规则 //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) //析构函数(空实现) //拷贝函数(值拷贝) //2.如果我们写了有参构造函数 编译器就不会提供默认构造函数 但是会提供拷贝构造函数 //3.如果我们写了拷贝函数 编译器就不再提供 默认 有参 构造函数
//构造函数调用规则 #include <iostream> using namespace std; //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) ...
随机推荐
- [刘阳Java]_Spring AOP基于XML配置介绍_第9讲
基于注解配置的Spring AOP固然简单,但是这节我们会给大家介绍基于XML配置的AOP是如何应用的.为什么这么说了,因为后面我们还会介绍到Spring对Dao操作的事务管理(基于AOP的XML文件 ...
- File类与常用IO流第一章File类
第一章:File类 一.1个重点单词: file:文件:directory:文件夹/目录:path:路径(绝对路径:absolutePath) 二.4个静态成员变量: 1.static String ...
- SpringBoot总结之事务和AOP
一.事务 在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框架会自动默认分别注入DataS ...
- python -- 程序结构
一.程序结构 • 定义python文件的头部模板:在File->Settings->Editor->File and Code Templates->Python script ...
- 看懂UML类图笔记
在学习设计模式的时候,经常会遇到UML类图,所以就找了一些资料,做一些笔记. 从一个示例开始 下面这个类图,类之间的关系是我们需要关注的: 车的类图结构为<<abstract>> ...
- 更改Nginx网站根目录以及导致的403 forbidden问题
Nginx采用默认配置,只修改了root的网站根目录位置,再访问网站的时候提示403Forbidden的错误. 仔细检查了新文件夹的权限,也对比了心就网站根目录的权限,都是一样的. 最后尝试关闭了SE ...
- MYSQL一个设备上的主从复制实现-windows
只记录一次在一个设备上实现mysql主从复制的过程,很详细,建议收藏,用到的时候照着步骤做就可以,会记录所有需要注意到的细节和一些容易遇到的坑以及解决办法! 如果需要在同一台电脑(服务器)上实现mys ...
- 图像旋转的FPGA实现(一)
继续图像处理专题,这次写的是图像旋转.若要说小分辨率的图像旋转倒也简单,直接将原始图像存储在BRAM中,然后按照旋转后的位置关系取出便是.但是对于高分辨的图像(720P及以上)就必须得用DDR3或者D ...
- 2019版pycharm永久激活
链接:https://pan.baidu.com/s/1vY1KBvi2NHIgoN8C2qaFbg 提取码:p4gx 1.下对应版本的jar包,放到pycharm目录的bin目录下2.去C:\Use ...
- 谈谈 C++ STL 中的迭代器
C++中的迭代器和指针 在前面的内容中我们简单讲过,STL主要是由三部分组成 容器(container),包括vector,list,set,map等 泛型算法(generic algorithm), ...