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 ...
随机推荐
- 第 8 章 容器网络 - 060 - 在 Docker 中使用 flannel
在 Docker 中使用 flannel 编辑 host1 的 Docker 配置文件 /etc/systemd/system/docker.service.d/10-machine.conf 设置 ...
- Virtualbox主机和虚拟机之间文件夹共享及双向拷贝
把文件发到VirtualBox的方法有很多,下面推荐两种: 1.把要共享的文件夹挂载到虚拟机某一个文件上: (1)打开虚拟机的设置,点击左边的“共享文件夹”,点击带加号的文件按钮,在文件夹路径选择要共 ...
- English trip EM2-PE-6A Family Relationship Teacher:Taylor
课上内容(Lesson) What's your name? Where is your hometown? 你的家乡是哪里? Where do you come from? 你从哪里来? ...
- Django多表查询练习题
#一 model表:from django.db import models # Create your models here. class Teacher(models.Model): tid=m ...
- Vrrp和Hsrp的区别
VRRP原理协议简述简单来说,VRRP是一种容错协议,它为具有组播或广播能力的局域网(如以太网)设计,它保证当局域网内主机的下一跳路由器出现故障时,可以及时的由另一台路由器来代替,从而保持通讯的连续性 ...
- Roman To Integer leetcode java
问题描述: Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range fr ...
- 【微信公众号开发】【8】网页授权获取用户基本信息(OAuth 2.0)
前言: 1,在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名. 请注意,这 ...
- Jupyter Notebook入门教程
Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言.在本文中,我们将介绍 Jupyter notebook 的主要特性,以 ...
- virtualbox 中centOS在不能ssh
这个重要跟虚拟机的网络设置有关系.废话不多说. 针对一个网卡的形式.可以如下进行配置 1.网络-- 连接方式还选择“网络地址转换(NAT)” 其他不变,展开高级,设置端口转发 主机IP设为本机IP, ...
- Nodejs--util模块
util.inspect util.inspect是一个将任意对象转换 为字符串的方法,通常用于调试和错误输出. 它至少接受一个参数 object,即要转换的对象. util.inspect(obje ...