C++构造函数和析构函数,以及构造函数特殊成员变量和函数的初始化
body, table{font-family: 微软雅黑; font-size: 10pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}
1. 类和对象
2. 构造函数
|
3. 析构函数
4. 复制构造函数
|
5. 特殊成员变量的初始化
6. 特殊成员函数
|
Point(int x=0,int y=0):xpos(x),ypos(y); //初始化顺序只跟数据成员声明时的顺序有关,与其在初始化列表中的顺序无关
初始化成员列表的赋值语句先执行,构造函数体中的赋值语句后执行。
|
Point()
:xPos(0)
,yPos(0)
{}
Point(int x,int y)
:xPos(x)
,yPos(y)
{}
|
Point(int x=0,int y=0)
:xPos(x)
,yPos(y)
{}
Point(int iy )
: _iy(iy) //初始化列表
, _ix(_iy)
{}
|
~computer() { delete []point; point = NULL; //要显示调用就要有这个,不然会应为重复释放出现内存错误 } |
#include <iostream>
#include<string.h>
using namespace std;
class Computer
{
private:
char *brand;
float price;
public:
Computer(const char* brand1,float price1)
:price(price1)
{
cout<<"构造函数:"<<endl;
brand=new char[strlen(brand1)+1];
strcpy(brand,brand1);
}
~Computer()
{
delete []brand;
cout<<"析构函数:"<<endl;
}
void print()
{
cout<<"品牌:"<<brand<<endl;
cout<<"价格:"<<price<<endl;
}
};
|
#include"Computer.h"
Computer pc("Mac",49999); //先于main执行,调用构造函数;
int main()
{
cout<<"Enter main"<<endl;
pc.print();
Computer *p=new Computer("lenovo",4000);
p->print();
delete p;
//new 创建的对象,delete 才调用析构函数
return 0;
}
|
point p1(2,3); point p2=p1 或者 point p2(p1); 定义: point::point(const point&); //可以在函数体实现整个函数复制过程,也可以用初始化成员列表 |
point(const point & pt) //复制构造函数的定义及实现
{
cout << "调用复制构造函数" << endl;
xPos = pt.xPos;
yPos = pt.yPos;
}
|
//pt在class里面,所以也可以直接访问私有成员
point(const point & pt):xPos(pt.xPos),yPos(pt.yPos)
{
cout << "调用复制构造函数" << endl;
}
|
computer comp2(comp1)等价于: //浅拷贝
comp2.brand = comp1.brand; //简单的指针复制,两个指向同一个内存区域
comp2.price = comp1.price;
|
//浅拷贝
#include<iostream>
#include<string.h>
using namespace std;
class computer
{
private:
char * brand;
float price;
public:
computer(const char*sz,float p)
{
brand=new char[strlen(sz)+1];
strcpy(brand,sz);
price=p;
}
computer(const computer &cp):brand(cp.brand),price(cp.price)
//拷贝构造函数,简单拷贝,浅拷贝,两个相同指针指向同一个内存区域
{
cout<<"调用复制构造函数"<<endl;
}
~computer()
{
delete []brand;
brand=NULL;
cout<<"调用析构函数释放资源"<<endl;
}
void print()
{
cout<<"品牌:"<<brand<<endl;
cout<<"价格:"<<price<<endl;
}
};
int main()
{
computer com1("联想",4999.99);
com1.print();
computer com2(com1);
com2.print();
//程序结束,两次调用析构函数释放new申请的对空间,产生错误
return 0;
}
|
//深拷贝
#include <iostream>
#include<string.h>
using namespace std;
class computer
{
private:
char * brand;
float price;
public:
computer(const char*sz,float p)
{
brand=new char[strlen(sz)+1];
strcpy(brand,sz);
price=p;
}
computer(const computer & cp ) //拷贝构造函数,深拷贝
{
cout<<"调用复制构造函数"<<endl;
brand=new char[strlen(cp.brand)+1]; //对象自己开辟堆空间
strcpy(brand,cp.brand); //对象指针指向自己开辟的对空间
price=cp.price;
}
~computer()
{
delete []brand;
brand=NULL;
cout<<"调用析构函数释放资源"<<endl;
}
void print()
{
cout<<"品牌:"<<brand<<endl;
cout<<"价格:"<<price<<endl;
}
};
int main()
{
computer com1("联想",4999.99);
com1.print();
computer com2(com1);
com2.print();
//两个对象都指向各自开辟的对空间,调用两次析构函数释放资源就不会出错
return 0;
}
|
#include<iostream>
using namespace std;
class point
{
private:
int _x;
int _y;
public:
#if 0
point(int x=0,int y=0)
:_x(x)
,_y(y)
{
cout<<"point(int,int)"<<endl;
}
#endif
explicit point(int x,int y)
:_x(x)
,_y(y)
{
cout<<"point(int,int)"<<endl;
}
explicit point()
{
cout<<"point()"<<endl;
}
point & operator = (const point &rhs)
{
this->_x = rhs._x;
this->_y = rhs._y;
cout<<"operator=(const point&)"<<endl;
}
void print()
{
cout<<"("<<_x<<","<<_y<<")"<<endl;
}
};
|
int main()
{
point pt1(3,4);
point pt2 = pt1; //这里调用默认的拷贝构造函数
pt2.print();
//point pt3 = 1; //加了关键字explicit,禁止这种转换
//pt3.print();
point pt4(pt1);
pt4.print();
return 0;
}
|
#include <iostream>
using namespace std;
class point
{
private:
int ix;
int iy;
public:
point(int ix1=0,int iy1=0)
:ix(ix1)
,iy(iy1)
{
cout<<"构造函数:"<<endl;
}
point(const point &rhs)
:ix(rhs.ix)
,iy(rhs.iy)
{
cout<<"拷贝构造函数:const"<<endl;
}
point( point &rhs)
:ix(rhs.ix)
,iy(rhs.iy)
{
cout<<"拷贝构造函数:"<<endl;
}
void print()
{
cout<<"("<<ix<<","<<iy<<")"<<endl;
}
void print()const
{
cout<<"print const"<<endl;
cout<<"("<<ix<<","<<iy<<")"<<endl;
}
};
|
int main()
{
const point p1(3,4);
p1.print();
//p1是const,print()函数也必须是const
point p2(p1);
//const成员变量,类中没有显示定义拷贝构造函数,可以调用缺省拷贝构造函数,但是如果显示定义,那么函数必须有关键字const
p2.print();
return 0;
}
|
///
/// @file destruct.cpp
/// @author meihao1203(meihao19931203@outlook.com)
/// @date 2017-12-17 10:01:36
///
// -fno-elide-constructors
// 编译器有返回值优化,要看到return 对象发生的赋值构造函数,就要加上面的命令
// 代码第一个输出结果是有构造函数的,第二个是无构造函数的
// 每次例子前的解释。。。不懂,以输出结构为准
#include<iostream>
using namespace std;
class point
{
private:
int _x;
int _y;
public:
point()
{
cout<<"默认构造函数"<<this<<" "<<endl;
_x = 0;
_y = 0;
}
//带一个参数的可用于类型转换的构造函数
point(int x)
{
cout<<"1参数构造函数"<<this<<" "<<endl;
_x = x;
_y = 0;
}
//带参数的构造函数
point(int x,int y)
{
cout<<"2参数构造函数"<<this<<" "<<endl;
_x = x;
_y = y;
}
//拷贝构造函数,如果此函数不定义,系统将生成缺省拷贝构造函数功能,
//缺省拷贝构造函数的行为是:用传入的对象参数的成员初始化正要建立的对象的相应成员
point(const point &p)
{
cout<<"拷贝构造函数"<<this<<" "<<endl;
_x = p._x;
_y = p._y;
}
point &operator=(const point &p)
{
cout << "赋值运算符重载函数 " << this << " " << endl;
if(this!=&p) //=两边不是同一个
{
_x = p._x;
_y = p._y;
}
return (*this);
}
//析构函数,一个类中只能有一个析构函数,如果用户没有定义析构函数,
//系统会自动未类生成一个缺省的析构函数
#if 1
~point()
{
cout << "析构函数 " << this << " " << endl;
}
#endif
};
point func1()
{
point a;
return a;
}
|
int main()
{
//当有析构函数的时候,Point()不会调用构造函数生成临时的匿名对象。
//当没有析构函数的时候,Point()会生成一个临时的匿名对象,等价于Point pt1;这句话只会调用无参构造函数,不会调用拷贝构造函数
//point pt1 = point(); //只调用一次构造函数
//point(); //会调用默认构造函数的
//默认构造函数0x7ffd6a109ef0
//拷贝构造函数0x7ffd6a109ee0
//析构函数 0x7ffd6a109ef0
//析构函数 0x7ffd6a109ee0
//
//默认构造函数0x7ffdec3a5a40
//拷贝构造函数0x7ffdec3a5a30
//当有析构函数的时候,CPoint(1)不会生成调用构造函数生成临时的匿名对象。
//当没有析构函数的时候,CPoint()会生成一个临时的匿名对象,等价于CPoint pt(1);这句话只会调用一个参数的构造函数,不会调用拷贝构造函数
//point pt2 = point(1);
//1参数构造函数0x7ffc3b5a3360
//拷贝构造函数0x7ffc3b5a3350
//析构函数 0x7ffc3b5a3360
//析构函数 0x7ffc3b5a3350
//
//1参数构造函数0x7ffc533a4ba0
//拷贝构造函数0x7ffc533a4b90
//普通数据类型转换为类类型,利用相应的构造函数就可以实现。等价于CPoint pt(1);
//point pt3 = 1;
//1参数构造函数0x7fff4bcbea20
//拷贝构造函数0x7fff4bcbea10
//析构函数 0x7fff4bcbea20
//析构函数 0x7fff4bcbea10
//
//1参数构造函数0x7ffca3575720
//拷贝构造函数0x7ffca3575710
/*拷贝构造函数与赋值运算符重载函数的区别:
*1. 拷贝构造函数是用已经存在的对象的各成员的当前值来创建一个相同的新对象。
* 在下述3种情况中,系统会自动调用所属类的拷贝构造函数。
* 1.1 当说明新的类对象的同时,要给它赋值另一个已经存在对象的各成员当前值。
* 1.2 当对象作为函数的赋值参数而对函数进行调用要进行实参和形参的结合时。
* 1.3 当函数的返回值是类的对象,在函数调用结束后返回主调函数处的时候。
*2. 赋值运算符重载函数要把一个已经存在对象的各成员当前值赋值给另一个已经存在的同类对象*/
//point pt4;
//point pt5 = pt4;
//有析构函数
//默认构造函数0x7ffc2ba82f80
//拷贝构造函数0x7ffc2ba82f90
//析构函数 0x7ffc2ba82f90
//析构函数 0x7ffc2ba82f80
//调用无参构造函数,拷贝构造函数,此处如果没有写析构函数,则还会调用一次拷贝构造函数
//因为函数返回会生成一个临时对象,然后再将这个临时对象赋值给pt6,所以多调用一次拷贝构造函数;
//如果有析构函数,则不会生成中间的临时变量,所以少一次拷贝构造函数的调用
//point pt6 = func1();
// -fno-elide-constructors 编译带上这个命令才看的到
//默认构造函数0x7fff3eaa2a50
//拷贝构造函数0x7fff3eaa2a90
//析构函数 0x7fff3eaa2a50
//拷贝构造函数0x7fff3eaa2a80
//析构函数 0x7fff3eaa2a90
//析构函数 0x7fff3eaa2a80
//func1()先执行,point a return的时候发生拷贝构造函数,完了析构a, = 发生拷贝,最后返回的匿名对象析构,pt6 析构
//
//默认构造函数0x7ffc26728660
//拷贝构造函数0x7ffc26728690
//拷贝构造函数0x7ffc26728680
point pt7(1,2);
point pt8;
pt8 = pt7;
//2参数构造函数0x7ffeded09530
//默认构造函数0x7ffeded09540
//赋值运算符重载函数 0x7ffeded09540
//析构函数 0x7ffeded09540
//析构函数 0x7ffeded09530
}
|
C++构造函数和析构函数,以及构造函数特殊成员变量和函数的初始化的更多相关文章
- Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序
当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢? (1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法: (2).如果类已经加载过 ...
- C++成员变量与函数内存分配
关于结构体和C++类的内存地址问题 C++类是由结构体发展得来的,所以他们的成员变量(C语言的结构体只有成员变量)的内存分配机制是一样的.下面我们以类来说明问题,如果类的问题通了,结构体也也就没问题啦 ...
- C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化
C++类有几种类型的数据成员:普通类型.常量(const).静态(static).静态常量(static const).这里分别探讨以下他们在C++11之前和之后的初始化方式. c++11之前版本的初 ...
- java类成员变量与代码块初始化
首先根据下面的这个一段代码:引入关于java初始化顺序的问题public class InitationTest extends Person { public InitationTest() { S ...
- java成员变量和局部变量的初始化和内存中的运行机制
成员变量: 当系统加载类或创建类的实例时,系统会自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值. eyeNum是类属性.name是实例属性 所有person实例访问eyeNu ...
- java中static修改成员变量和函数和其他使用
一.通过static修饰的成员变量初始化只会初始化一次 //静态变量初始化只会初始化一次 public class zuishuai { public static void main(String[ ...
- C++ struct结构体定义构造函数和析构函数,构造函数参数从VS2017平台转换到Qt5平台下构建出错,采用字符集转换函数将string类型转换为wstring,构建仍然出错!
调试win硬件驱动,需要利用VS编译的win驱动构建自己的Qt5GUI程序: 其中部分win驱动源码如下 device_file::device_file(const std::string& ...
- C++列表初始化是初始化本类自身含有的成员变量,不能直接初始化继承过来的成员变量
在构造函数体内赋值就是对的了
- Delphi会自动初始化全局变量和类成员变量,但不初始化局部变量
If you don't explicitly initialize a global variable, the compiler initializes it to 0. Object insta ...
随机推荐
- Python Selenium 文件下载
Python Selenium 进UI自动化测试时都会遇到文件上传和下载的操作,下面介绍一下文件下载的操作 这里介绍使用FireFox浏览器进行文件下载的操作. 1.设置文件默认下载地址 如下图,fi ...
- 分享:selenium(一) xpath
xpath无所不能定位. https://www.w3.org/TR/xpath/all/#axes 两个神器:firebug.xpath-checker 举例:混合定位 //td[a//fron ...
- 关于TeeChart使用我会持续更新
关于TeeChart使用我会持续更新 这篇文章中我是在Winform窗体使用TeeChart2011控件,通过定时器实现了实时绘制曲线图(三个序列). 先上一下效果图: 1.TeeChart2011. ...
- linux下编译C/C++ 程序
C/C++的速度是Python和perl所无法比拟的,尤其对于处理超大的生物信息学文件来说. 最近在写一个最简单的fastq cut工具,Python简直慢到不能忍,8G的fastq.gz文件的cut ...
- 20165327 2017-2018-2 《Java程序设计》第一周学习总结
第1章 Java入门 一.Java 的特点 简单 面向对象 平台无关 多线程:允许同时完成多个任务 动态:Java程序的基本组成单元就是类(有些类是自己编写的,有一些是从类库中引入的,而类又是运行时动 ...
- LeetCode--013--罗马数字转整数(java)
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...
- LeetCode--414--第三大的数
问题描述: 给定一个非空数组,返回此数组中第三大的数.如果不存在,则返回数组中最大的数.要求算法时间复杂度必须是O(n). 示例 1: 输入: [3, 2, 1] 输出: 1 解释: 第三大的数是 1 ...
- java测试感想
package ATM; public class Account { private String accountID; private String accountname; private St ...
- 宽度优先搜索BFS(Breadth-First-Search)
Breadth-First-Search 1. 与DFS的异同 相同点:搜索所有可能的状态. 不同点:搜索顺序. 2. BFS总是先搜索距离初始状态近的状态,它是按照:开始状态->只需一次转移就 ...
- spring boot(二十)使用spring-boot-admin对服务进行监控
上一篇文章<springboot(十九):使用Spring Boot Actuator监控应用>介绍了Spring Boot Actuator的使用,Spring Boot Actuato ...