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(void)
{
m_real = 0.0;
m_imag = 0.0;
}
// 一般构造函数(也称重载构造函数)
// 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)
// 例如:你还可以写一个 Complex( int num)的构造函数出来
// 创建对象时根据传入的参数不同调用不同的构造函数
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;
}
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象,
//需要注意的一点是,这个其实就是一般的构造函数,但是对于出现这种单参数的构造函数,C++会默认将参数对应的类型转换为该类类型,有时候这种隐私的转换是我们所不想要的,所以需要使用explicit来限制这种转换。
Complex(double r)
{
m_real = r;
m_imag = 0.0;
}
// 等号运算符重载(也叫赋值构造函数)
// 注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建
// 若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作
Complex &operator=( const Complex &rhs )
{
// 首先检测等号右边的是否就是左边的对象本身,若是本对象本身,则直接返回
if ( this == &rhs )
{
return *this;
}
// 复制等号右边的成员到左边的对象中
this->m_real = rhs.m_real;
this->m_imag = rhs.m_imag;
// 把等号左边的对象再次传出
// 目的是为了支持连等 eg: a=b=c 系统首先运行 b=c
// 然后运行 a= ( b=c的返回值,这里应该是复制c值后的b对象)
return *this;
}
};
下面使用上面定义的类对象来说明各个构造函数的用法:
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;
// 调用类型转换构造函数
// 系统首先调用类型转换构造函数,将5.2创建为一个本类的临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
c2 = 5.2;
// 调用拷贝构造函数( 有下面两种调用方式)
Complex c5(c2);
Complex c4 = c2; // 注意和 = 运算符重载区分,这里等号左边的对象不是事先已经创建,故需要调用拷贝构造函数,参数为c2
//这一点特别重要,这儿是初始化,不是赋值。其实这儿就涉及了C++中的两种初始化的方式:复制初始化和赋值初始化。其中c5采用的是复制初始化,而c4采用的是赋值初始化,这两种方式都是要调用拷贝构造函数的。
}
三、思考与测验
1. 仔细观察复制构造函数
Complex(const Complex & c)
{
// 将对象c中的数据成员值复制过来
m_real = c.m_real;
m_img = c.m_img;
}
为什么函数中可以直接访问对象c的私有成员?
答:(网上)因为拷贝构造函数是放在本身这个类里的,而类中的函数可以访问这个类的对象的所有成员,当然包括私有成员了。
===========================以上转自:http://www.cnblogs.com/xkfz007/archive/2012/05/11/2496447.html===============
四、引用与值传递的区别
调试以下代码可以发现:#include <iostream>using namespace std;class Complex
{
private :
double m_real;
double m_imag;
int id;
static int counter;
public:
// 无参数构造函数
Complex(void)
{
m_real = 0.0;
m_imag = 0.0;
id=(++counter);
cout<<"Complex(void):id="<<id<<endl;
}
// 一般构造函数(也称重载构造函数)
Complex(double real, double imag)
{
m_real = real;
m_imag = imag;
id=(++counter);
cout<<"Complex(double,double):id="<<id<<endl;
}
// 复制构造函数(也称为拷贝构造函数)
Complex(const Complex & c)
{
// 将对象c中的数据成员值复制过来
m_real = c.m_real;
m_imag = c.m_imag;
id=(++counter);
cout<<"Complex(const Complex&):id="<<id<<" from id="<<c.id<<endl;
}
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象
Complex(double r)
{
m_real = r;
m_imag = 0.0;
id=(++counter);
cout<<"Complex(double):id="<<id<<endl;
}
~Complex()
{
cout<<"~Complex():id="<<id<<endl;
}
// 等号运算符重载
Complex &operator=( const Complex &rhs )
{
if ( this == &rhs ) {
return *this;
}
this->m_real = rhs.m_real;
this->m_imag = rhs.m_imag;
cout<<"operator=(const Complex&):id="<<id<<" from id="<<rhs.id<<endl;
return *this;
}
};
int Complex::counter=;
Complex test1(const Complex& c)
{
return c;
}
Complex test2(const Complex c)
{
return c;
}
Complex test3()
{
static Complex c(1.0,5.0);
return c;
}
Complex& test4()
{
static Complex c(1.0,5.0);
return c;
}
int main()
{
Complex a,b; // 下面函数执行过程中各会调用几次构造函数,调用的是什么构造函数?
//=====================================================
Complex c=test1(a);//如图一
Complex d=test2(a);//如图一
//test1(a);//如图二
//test2(a);//如图二
//此处体现了值传递与引用传递的区别,也体现了带返回值函数有无接收对象时的不同(是否析购),同时,体现了return 语句建立的是临时对象,接收对象是临时对象的 引用而不是赋值!(此处是个人的理解,理由是有接收之后就没有了临时对象的析购,说明对象占用的空间没有被释放)
//=======================================================
b = test3();
b = test4(); Complex e=test2(1.2);
Complex f=test1(1.2);
Complex g=test1(Complex(1.2));
return ;
}
图一
图二
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的第三个构造函数的第 ...
随机推荐
- (转)C# 选择正确的集合
原文: http://www.cnblogs.com/luminji/archive/2011/03/24/1993393.html 要选择正确的集合,我们首先要了解一些数据结构的知识.所谓数据结构, ...
- T-SQL 查询数据库中各个表的使用空间
1. 查询单表 EXEC sp_spaceused 'dbo.tablename' 2. 查询所有表 SELECT t.NAME AS TableName, s.Name AS SchemaName, ...
- 基础拾遗------redis详解
基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗----- ...
- php-cgi not found
错误描述 用PHPStorm运行PHP脚本的时候浏览器提示"502 Bad Gateway",PHPStorm提示"php-cgi not found". 系统 ...
- Maven build lifecycle
Clean Lifecycle 运行mvn clean执行clean生命周期,包含三个生命周期阶段: pre-clean clean post-clean clean:clean会删除一次构建后的输出 ...
- Bootsrap基本应用
Bootsrap 用法: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
- DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”
DeveloperExceptionPageMiddleware中间件如何呈现"开发者异常页面" 在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式&g ...
- html drag api 在firefox 下 拖动出现新窗口的解决办法
有个功能,需要用drag drop api 来做. 发现在firefox下拖放,会出现新的tab 页签,即使在ondragover.ondrop中使用了event.preventDefault也无济于 ...
- SASS 入门笔记
参考资料: SASS 用法指南 SASS 语法 Sass Basics SASS_REFERENCE sass 有两种后缀名文件:一种后缀名为 sass,不使用大括号和分号:另一种就是我们这里使用的 ...
- 《如何正确学习JavaScript》读后小结
在segmentfault上读的一篇学习JavaScript路线的文章,做个小结. 一.简介.数据类型.表达式和操作符 (1)<JavaScript权威指南>前言1-2章&< ...