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的第三个构造函数的第 ...
随机推荐
- 用gcc进行程序的编译
在Linux系统上,一个档案能不能被执行看的是有没有可执行的那个权限(x),不过,Linux系统上真正认识的可执行文件其实是二进制文件(binary program),例如/usr/bin/passw ...
- Play Framework 完整实现一个APP(十四)
添加测试 ApplicationTest.java @Test public void testAdminSecurity() { Response response = GET("/adm ...
- js动态添加事件-事件委托
作者:白狼 出处:http://www.manks.top/javascript-dynamic-event.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给 ...
- vi(vim)键盘图及其基本命令
进入vi vi filename 打开或新建文件,并将光标置于第一行首 vi +n filename 打开文件,并将光标置于第 n行首 vi + fi ...
- 30天的php学习之路——第一天开端
因项目紧急只留给了我4周时间学习php.谨以此文记录我的php学习历程,仅供参考,若有错误请指正. 之前对php有过一些了解,一些语法和习惯和C#差距有些大,所以第一天准备对php中的符号有个全面的了 ...
- monkey之monkey命令详解
四大类-- 常用选项.事件选项.约束选项.调试选项 1.常用选项 --help:打印帮助信息 -v:指定打印信息的详细级别,一个-v增加一个级别 ,默认级别为 0 .用于指定反馈信息级别(信息级别就是 ...
- OC中加载html5调用html方法和修改HTML5内容
1.利用webView控件加载本地html5或者网络上html5 2.设置控制器为webView的代理,遵守协议 3.实现代理方法webViewDidFinishLoad: 4.在代理方法中进行操作H ...
- Python Socket 网络编程
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
- Webform:Application、ViewState对象的用法
Application Application对象的作用范围是整个全局,也就是说对所有用户都有效.它在整个应用程序生命周期中都是有效的,类似于使用全局变量一样,所以可以在不同页面中对它进行存取.它和S ...
- [bzoj1007][HNOI2008][水平可见直线] (斜率不等式)
Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为 可见的,否则Li为被覆盖的. 例如,对于直线: L1:y ...