C++之类与对象(2)
接着上一节,今天讲C++中类的构造函数与析构函数,对象的赋值与复制.
1.用过C#语言的人,都知道构造函数是一种特殊的成员函数,它主要用于对对象分配空间,进行初始化。构造函数的名字必须与类名相同。可以有任何类型的参数,但不返回任何值,是在建立对象时自动执行的。和上一节一样,还是用Kid类来说明。
1 class Kid 2 { 3 private: 4 int age; 5 char*name; 6 char*sex; 7 public: 8 Kid(int age,char*name,char*sex); 9 void showKid();10 };11 12 Kid::Kid(int age,char*name,char*sex)13 {14 Kid::age=age;15 Kid::name=name;16 Kid::sex=sex;17 }18 19 void Kid::showKid()20 {21 cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;22 }
接下来,建立对象并初始化:Kid kid(10,"rookie_j","男");另外一种使用new运算符动态建立对象:Kid *ptr=new Kid(10,"rookie_j","男");通过指针变量ptr来访问:ptr->showKid();当我们用new建立对象时,当不再使用它时,要用delete运算符释放它:delete ptr;和不同成员函数一样,如果构造函数定义在类体内部,则作为内联函数处理;
在声明类时,对数据成员的初始化一般在构造函数中用赋值语句进行,但C++还提供了另外一种初始化数据成员的方法——用成员初始化表来实现对数据成员的初始化。它的一般形式为:类名::构造函数名([参数表]):[(成员初始化表)];成员初始化表的形式为:成员名1(初始值1),成员名2(初始值2),成员名2(初始值2);比如:
Kid::Kid(int age,char *name,char *sex):age(age),name(name),sex(sex){};
接下来讲一下析构函数:在我第一次在C++里看到这个名词时,感觉这个知识点很深奥,结果看了以后,其实很简单。它的作用和构造函数刚好相反,用于撤销对象,如:释放分配给对象的内存空间。析构函数和构造函数名相同,但在其前面要加~符号,析构函数没有参数,也没有返回值,且不能重载,因此一个类中只有一个析构函数。以下三种情况,当对象的生命周期结束时,析构函数会被自动调用:(1)定义了全局对象,则在程序流程离开其作用域(如:main函数结束或调用Exit)时,调用该全局对象的析构函数;(2)对象被定义在函数体里,则当这个函数执行完后,该对象释放,析构函数被自动调用;(3)若一个对象使用new运算符动态创建的,在使用delete运算符释放它时,会自动调用析构函数;
1 #include "stdafx.h" 2 #include <iostream> 3 4 usingnamespace std; 5 6 class Kid 7 { 8 private: 9 int age;10 char*name;11 char*sex;12 public:13 Kid(int age,char*name,char*sex);14 ~Kid();15 void showKid();16 };17 18 19 Kid::Kid(int age,char*name,char*sex)20 {21 Kid::age=age;22 Kid::name=newchar[strlen(name)];23 strcpy(Kid::name,name);24 Kid::sex=newchar[strlen(sex)];25 strcpy(Kid::sex,sex);26 }27 28 Kid::~Kid()29 {30 cout<<"dispose object kid"<<endl;31 delete []name;32 delete []sex;33 }34 35 void Kid::showKid()36 {37 cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;38 }39 40 41 int main()42 {43 Kid kid(10,"rookie_j","男");44 kid.showKid();45 46 Kid *ptr=new Kid(10,"rookie_x","女");47 ptr->showKid();48 49 delete ptr;50 51 return0;52 }
结果:
如果没有给类定义构造函数,则编译系统自动地生成一个默认的构造函数,比如在Kid类中编译系统会为其产生一个Kid::Kid(){};构造函数,这个默认的构造函数只能给对象开辟存储空间,不能给数据成员赋值,这时数据成员的初值就是随机数。对没有定义构造函数的类,其公有数据成员可以用初始化值表进行初始化,如:
1 class Kid 2 { 3 public: 4 int age; 5 char*name; 6 char*sex; 7 }; 8 9 int main()10 {11 12 Kid kid={10,"Rookie_j","男"};13 cout<<"姓名:"<<kid.name<<endl<<"年龄:"<<kid.age<<endl<<"性别:"<<kid.sex<<endl;14 15 return0;16 }
但只要一个类定义了构造函数,系统将不再给它提供默认构造函数;另外还有默认的析构函数(Kid::~Kid(){}),一般来说默认的析构函数就能满足要求,但对一些需要做一些内部处理的则应该显式定义析构函数。带默认参数的构造函数和之前所说的带参数的成员函数是一样的,对于构造函数的重载,在这里我就不多说了,只想强调一点,如果是无参的构造函数创建对象,应该使用"类名 对象名"的形式,而不是"类名 对象名()";
2.对象的赋值其实和变量的赋值差不多,也是用赋值运算符=进行的,只不过进行赋值的两个对象的类型必须相同,对象之间的赋值只是数据成员的赋值,而不对成员函数赋值;
1 #include "stdafx.h" 2 #include <iostream> 3 4 usingnamespace std; 5 6 class Kid 7 { 8 private: 9 int age;10 char*name;11 char*sex;12 public:13 Kid(int age,char*name,char*sex);14 Kid(){ };15 ~Kid();16 void showKid();17 };18 19 20 Kid::Kid(int age,char*name,char*sex)21 {22 Kid::age=age;23 Kid::name=newchar[strlen(name)];24 strcpy(Kid::name,name);25 Kid::sex=newchar[strlen(sex)];26 strcpy(Kid::sex,sex);27 }28 29 Kid::~Kid()30 {31 cout<<"dispose object kid"<<endl;32 delete []name;33 delete []sex;34 }35 36 void Kid::showKid()37 {38 cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;39 }40 41 int main()42 {43 Kid kid(10,"rookie_j","男"),kid2;44 kid.showKid();45 46 kid2=kid;47 kid2.showKid();48 49 return0;50 }
结果:
拷贝构造函数是一种特殊的构造函数,其形参是类对象的引用。它主要用于在建立一个新的对象时,使用已经存在的对象去初始化这个新对象。拷贝构造函数也是构造函数,所以函数名必须与类名相同,参数只有一个就是同类对象的引用,每个类必须要有一个拷贝构造函数。如果程序员自己不定义拷贝构造函数,系统会自动产生一个默认拷贝构造函数。调用拷贝构造函数的形式有代入法:类名 对象2(对象1)和赋值法:类名 对象2=对象1;
1 #include "stdafx.h" 2 #include <iostream> 3 4 usingnamespace std; 5 6 class Kid 7 { 8 private: 9 int age;10 char*name;11 char*sex;12 public:13 Kid(int age,char*name,char*sex);14 Kid(const Kid &kid);15 ~Kid();16 void showKid();17 };18 19 20 Kid::Kid(int age,char*name,char*sex)21 {22 Kid::age=age;23 Kid::name=newchar[strlen(name)];24 strcpy(Kid::name,name);25 Kid::sex=newchar[strlen(sex)];26 strcpy(Kid::sex,sex);27 }28 29 Kid::Kid(const Kid &kid)30 {31 Kid::age=kid.age*2;32 Kid::name=newchar[strlen(kid.name)];33 strcpy(Kid::name,kid.name);34 Kid::sex=newchar[strlen(kid.sex)];35 strcpy(Kid::sex,kid.sex);36 }37 38 Kid::~Kid()39 {40 cout<<"dispose object kid"<<endl;41 delete []name;42 delete []sex;43 }44 45 void Kid::showKid()46 {47 cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl;48 }49 50 int main()51 {52 Kid kid(10,"rookie_j","男");53 kid.showKid();54 55 Kid kid2(kid);56 kid2.showKid();57 58 Kid kid3=kid2;59 kid3.showKid();60 61 return0;62 }
结果:
同样的默认的拷贝构造函数:复制出与源对象的数据成员的值一样的新对象。调用拷贝构造函数的3种情况:(1)Kid kid2(kid1)或Kid kid2=kid1;(2)函数的形参是类的对象:fun(Kid kid){kid.showKid();}; int main(){Kid kid(10,"Rookie_j","男");fun(kid);return 0;};(3)函数返回值为类的对象:Kid fun(){Kid kid(10,"Rookie_j","男"); return kid;} int main(){ Kid kid; kid=fun();kid.showKid();return 0;};
3.最后还是一样用一个实例来总结一下今天所说的内容(开发工具:vs2010):
1 #include "stdafx.h" 2 #include <iostream> 3 4 usingnamespace std; 5 6 class Kid 7 { 8 private: 9 int age; 10 char*name; 11 char*sex; 12 public: 13 Kid(int age,char*name,char*sex); 14 Kid(const Kid &kid); //自定义拷贝函数 15 ~Kid(); 16 void showKid(); 17 }; 18 19 20 Kid::Kid(int age,char*name,char*sex) 21 { 22 Kid::age=age; 23 Kid::name=newchar[strlen(name)]; 24 strcpy(Kid::name,name); 25 Kid::sex=newchar[strlen(sex)]; 26 strcpy(Kid::sex,sex); 27 } 28 29 //Kid::Kid(int age,char *name,char *sex):age(age),name(name),sex(sex) //用成员初始化表对数据成员初始化 30 //{ 31 // 32 //} 33 34 Kid::Kid(const Kid &kid) 35 { 36 Kid::age=kid.age*2; 37 Kid::name=newchar[strlen(kid.name)]; 38 strcpy(Kid::name,kid.name); 39 Kid::sex=newchar[strlen(kid.sex)]; 40 strcpy(Kid::sex,kid.sex); 41 } 42 43 Kid::~Kid() //自定义析构函数 44 { 45 cout<<"dispose object kid"<<endl; 46 delete []name; //delete运算符释放存储空间 47 delete []sex; 48 } 49 50 void Kid::showKid() 51 { 52 cout<<"孩子:"<<endl<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl<<"性别:"<<sex<<endl; 53 } 54 55 class Car 56 { 57 public: 58 char*no; 59 char*brand; 60 int speed; 61 void showCar(); 62 ~Car(){};//仿默认析构 63 }; 64 65 66 67 void Car::showCar() 68 { 69 cout<<"汽车:"<<endl<<"号码:"<<no<<endl<<"品牌:"<<brand<<endl<<"速度:"<<speed<<"km/h"<<endl; 70 } 71 72 int main() 73 { 74 Kid kid(10,"rookie_j","男"); 75 kid.showKid(); 76 77 cout<<"--------------------"<<endl; 78 79 Kid kid2(kid); //代入法调用拷贝构造函数 80 kid2.showKid(); 81 82 cout<<"--------------------"<<endl; 83 84 Kid kid3=kid2; //赋值法调用拷贝构造函数 85 kid3.showKid(); 86 87 cout<<"--------------------"<<endl; 88 89 Kid *ptr=new Kid(10,"rookie_x","女"); //使用new运算符动态创建对象 90 ptr->showKid(); 91 92 cout<<"--------------------"<<endl; 93 94 //delete ptr; //释放对象所占的存储空间 95 96 Car car={"8888888","Benz",200},car2;//只有没定义构造函数的类,才能用初始值表初始化公有数据成员,默认构造 97 car.showCar(); 98 99 100 cout<<"--------------------"<<endl;101 102 car2=car;//默认拷贝构造函数或car2(car)103 car2.showCar();104 105 cout<<"--------------------"<<endl;106 107 return0;108 }
结果:
但在运行的时候,发现一个问题如果把delete ptr; 这句的注释去掉,结果汽车的情况就显示不出来了;
结果:
不知道为什么?求助各位大侠!
转载于:https://www.cnblogs.com/CaiNiaoZJ/archive/2011/07/24/2115041.html
C++之类与对象(2)相关推荐
- java_B站_面试题
Java面向对象有哪些特征,如何应用 面向对象编程是利用类和对象编程的一种思想.万物可归类,类是对于世界事物的高度抽象 ,不同的事物之间有不同的关系 ,一个类自身与外界的封装关系,一个父类和子类的 ...
- 史上最详细的23中设计模式解析,一个不落,理论搭配简单案例,更好理解哦
目录 一.软件设计模式的产生背景 二.软件设计模式的概念与意义 1. 软件设计模式的概念 2. 学习设计模式的意义 三.23 种设计模式的分类和功能 1. 根据目的来分 2. 根据作用范围来分 3. ...
- 在kotlin companion object中读取Bean,注入Bean对象
在kotlin companion object中读取Bean,注入Bean对象 在使用kotlin时,或多或少地会使用到一些公共组件,如 http. mongo. redis相关的组件. 使用组 ...
- IDEA自动生成对象所有set方法
idea中有一款插件能够生成对象所有的set方法,GenerateAllSetter :下载地址 步骤1:将下载好的压缩包放在自己记得的文件夹中,在idea中进行导入 步骤2:在本地选中刚才的压缩包, ...
- 基于Golang的对象序列化的程序包开发——myJsonMarshal
基于Golang的对象序列化的程序包开发--myJsonMarshal[阅读时间:约10分钟] 一.对象序列化概述 二.系统环境&项目介绍 1.系统环境 2.项目的任务要求 三.具体程序设计及 ...
- java 捕获异常并存入数据库_java异常处理,报异常的话怎么处理对象值,并持久化到数据库中...
展开全部 //没看到有人回e68a843231313335323631343130323136353331333365646233答你,我还没学到框架,不知道那个是不是可以很便捷操作你说的这样过程 / ...
- python程序如何执行死刑图片_如何判断对象已死
已死的对象就是不可能被任何途径使用的对象,有以下几种方法判断一个对象是否已经死了: 引用计数 给对象添加一个引用计数器,每当有一个地方引用他,计算器就加 1:当引用失效时,计数器减 1:任何时刻计数器 ...
- Go 学习笔记(64)— Go error.New 创建接口错误对象、fmt.Errorf 创建接口错误对象、errors.Is 和 errors.As
1. error 接口定义 除用 panic 引发中断性错误外,还可返回 error 类型错误对象来表示函数调用状态.error 接口是 Go 原生内置的类型,它的定义如下: // $GOROOT/s ...
- OpenCV 笔记(06)— Mat 结构、像素值存储方法、创建 Mat 对象各种方法、Mat 对象的运算
数字图像中的每个点都称为像素(对于图像元素),并且每个像素可以存储一个或多个值,这取决于它是否是仅存储一个值的黑白图像(也称为二进制图像,比如只存储0或1),还是存储两个值的灰度图像,或者是存储三个值 ...
- NumPy — 创建全零、全1、空、arange 数组,array 对象类型,astype 转换数据类型,数组和标量以及数组之间的运算,NumPy 数组共享内存
NumPy 简介 一个用 python 实现的科学计算包.包括: 1.一个强大的 N 维数组对象 Array : 2.比较成熟的(广播)函数库: 3.用于整合 C/C++ 和 Fortran 代码的工 ...
最新文章
- 嵌入式目标检测--Fast YOLO: A Fast You Only Look Once System for Real-time Embedded Object Detection
- Excel中条件格式应用的探讨之突出显示!
- crontab+php-cgi/php 定时执行PHP脚本
- origin master 出现The authenticity of host 'github.com ' can't be established
- Azure Services Platform
- 如何删除textarea的移动版Safari的阴影?
- enityframework 已连接的当前状态为打开。_关于性能优化 从tcp建立连接amp;断开的视角...
- c#使用zlib.net压缩解压byte数组
- js生成带log的二维码(qrcodejs)
- MySQL可视化工具之Navicat for MySQL
- C# JPG转PDF
- makefile终极目标
- 质量管理三个概念:QC、QA和QM 解析
- 怎么在python官网下载python,python的官方网址是什么
- 因子分析(factor analyis)
- DPDK环境搭建报错及解决方法总结
- 太乐地图下载器 V5.0.5 破解版
- 计算机网络课后答案(朱晓姝版)
- UVA 1645 Count——dp
- 公共域名服务DNS 114.114.114.114和8.8.8.8
热门文章
- (二叉树DFS)天平UVa 839
- js java post提交_如何从Express.js发送Post请求到另一个服务器(Java)?
- mtk android 5.1 logo,Android ROM DIY之MTK平台手机通用移植
- HTML+CSS+JS实现 ❤️绘制卡丁车动漫特效❤️
- 基于java(springboot+mybatis)汽车信息管理系统设计和实现以及文档
- arrays合并两个数组_每天一道力扣题: 88. 合并两个有序数组
- 二元函数洛必达求极限_洛必达法则的几个例子
- Java中12个原子操作类
- python tkinter数据库通讯录_TKINTER--GUI连接数据库登陆
- android studio viewo,Android Studio 之 ViewModel