C++学习系列笔记(三)
1、类和对象
声明类使用关键字class,并在他后面依次包含类名、一组放在{ }内的成员属性和方法以及结尾的分号。
class Human
{//Data attributes:string Name;string Gender;//Methods:void Talk(string TextToTalk);void IntroduceYouself( );……
} ;
就像int分配动态内存一样,也可以使用new为Human对象动态的分配内存;
Human* pAnotherHuman = new Human(); //动态的分配内存
delete pAnotherHuman;
使用句点运算符来访问成员
Human Tom;
Tom.DateBirth="1970";
使用指针运算符(->)访问成员
如果对象是使用new在自有储存区中实例化的,或者有指向对象的指针,则可以使用指针运算符(->)来访问成员属性和方法。
Human* pTom=new Human();
pTom->DataOfBirth="1970";
pTom->IntroduceYouself();
delete pTom;
下面结合代码来看一下:
#include<iostream>
#include<string>
using namespace std;class Human{private:string Name;int Age;public:void SetName(string HumansName){Name = HumansName;}void SetAge(int HumansAge){Age = HumansAge;}void IntroduceSelf(){cout << "I am" + Name << "and am";cout << Age << "years old" << endl;}};int main(){Human FirstMan;FirstMan.SetName("Adam");FirstMan.SetAge(30);FirstMan.IntroduceSelf();}
2、构造函数
构造函数是一种特殊的函数,它与类同名且不返回任何值。因此,Human类在声明内的构造函数声明类似于下面:
class Human
{public:Human( ){//代码}
};
在类声明外定义构造函数的代码如下:
class Human
{
public:Human( );};Human :: Human(){//代码}
::被称为作用域解析运算符。例如:Human::DateOfBirth指的是在Human类中声明的变量DateOfBirth,而::DateOfBirth表示全局作用域中的变量DateOfBirth。
包含初始化列表的构造函数的代码如下:
class Human
{
public:Human(string InputName = "Adam" , int Age = 25 ): Name(InputName) , Age(InputAge){//代码}
};
初始化列表由包含在括号当中的参数声明后面的冒号标识,冒号后面列出了各个成员变量及其初始化值。初始化值可以是参数,也可以是固定的值。
3、析构函数
析构函数在对象销毁时自动被调用。析构函数看起来也像一个与类同名的函数,但前面有一个波浪号(~)。因此,Human类的析构函数声明类似于下面这样,这是在类里面声明:
class Human
{
public:~Human( ){// code here}
};
在类声明外定义析构函数:
class Human
{
public:~Human();
};
Human::~Human()
{//code here
}
析构函数与构造函数的作用完全相反。析构函数是重置变量以及释放动态分配的内存和其他资源的理想场所。
析构函数典型代码如下:
#include<iostream>
#include<string>
using namespace std;
class MyString
{
private:char* Buffer;
public:MyString(const char* InitialInput){if (InitialInput != NULL){Buffer = new char[strlen(InitialInput + 1)];strcpy(Buffer, InitialInput);}elseBuffer = NULL;}~MyString(){cout << "Invoking destructor,cleaning up" << endl;if (Buffer != NULL)delete[] Buffer;}int GetLength(){return strlen(Buffer);}const char* GetString(){return Buffer;}
};
int main()
{MyString SayHello("Hello from string class:");cout << "string buffer in MyString is:" << SayHello.GetLength();cout << "characters long" << endl;cout << "Buffer contains:";cout << "Buffer contains:" << SayHello.GetString();
}
程序运行输出为:
string buffer in MyString is:24characters long
Buffer contains:Buffer contains:Hello from string class:Invoking destructor,cleaning up
析构函数不能重载,每个类都只能有一个析构函数。如果你忘记实现一个析构函数,编译器将创造一个伪(dummy)析构函数并调用他。伪析构函数为空,既不释放动态分配的内存。
复制构造函数
浅复制:复制类对象时,将复制其指针成员,都不复制指针指向的缓冲区,造成两个对象指向同一块动态分配的内存,会威胁程序的稳定性。
深复制:所以要将浅复制的参数复制变成地址传递,即按参数引用传递而不是进行二进制复制。代码示例如下
#include<iostream>
#include<string>
using namespace std;
class MyString
{
private:char* Buffer;
public:MyString(const char* InitialInput){cout << "Constructor:creating new String" << endl;if (InitialInput != NULL){Buffer = new char[strlen(InitialInput + 1)];strcpy(Buffer, InitialInput);cout << "Buffer points to:0x" << hex;cout << (unsigned int*)Buffer << endl;}elseBuffer = NULL;}//复制构造函数MyString(const MyString& CopySource){cout << "copy constructeor:copy from MyString" << endl;f (CopySource.Buffer != NULL){Buffer = new char[strlen(CopySource.Buffer) + 1];strcpy(Buffer, CopySource.Buffer);cout << "Buffer points to:0x" << hex;cout << (unsigned int*)Buffer << endl;}elseBuffer = NULL;}~MyString(){cout << "Invoking destructor,cleaning up" << endl;if (Buffer != NULL)delete[] Buffer;}int GetLength(){return strlen(Buffer);}const char* GetString(){return Buffer;}
};
void UseMyString(MyString Input)
{cout << "Sting Buffer in mystring is" << Input.GetLength();cout << "characters long" << endl;cout << "Buffer contains:" << Input.GetString() << endl;return;
}
int main()
{MyString SayHello("Hello from string class:");UseMyString(SayHello);
}
程序运行输出:
Constructor:creating new String
Buffer points to:0x004BD5A0
copy constructeor:copy from MyString
Buffer points to:0x004BD5E8
Sting Buffer in mystring is18characters long
Buffer contains:Hello from string class:
Invoking destructor,cleaning up
Invoking destructor,cleaning up
MyString包含原始指针成员char* Buffer,一般不要为类成员声明原始指针,而应该使用std::string。在没有原始指针的情况下,都不需要编写复制构造函数,这是因为编译器添加的默认复制构造函数将调用成员对象(如:std::string)的复制构造函数。
C++学习系列笔记(三)相关推荐
- 深度学习系列笔记——贰 (基于Tensorflow2 Keras搭建的猫狗大战模型 三)
深度学习系列笔记--贰 (基于Tensorflow Keras搭建的猫狗大战模型 一) 深度学习系列笔记--贰 (基于Tensorflow Keras搭建的猫狗大战模型 二) 前面两篇博文已经介绍了如 ...
- 深度学习系列笔记——贰 (基于Tensorflow Keras搭建的猫狗大战模型 一)
猫狗大战是著名的竞赛网站kaggle几年前的一个比赛,参赛者得到猫狗各12500张图片,作为训练集,另外还会得到12500张猫和狗的图片,作为验证.最后提交结果至kaggle平台,获得评测分数. 本篇 ...
- 深度学习入门教程UFLDL学习实验笔记三:主成分分析PCA与白化whitening
深度学习入门教程UFLDL学习实验笔记三:主成分分析PCA与白化whitening 主成分分析与白化是在做深度学习训练时最常见的两种预处理的方法,主成分分析是一种我们用的很多的降维的一种手段,通 ...
- Java命令学习系列(三)——Jmap
转载自 Java命令学习系列(三)--Jmap jmap是JDK自带的工具软件,主要用于打印指定Java进程(或核心文件.远程调试服务器)的共享对象内存映射或堆内存细节.可以使用jmap生成Heap ...
- CocosCreator项目学习系列lt;三gt;BattleCity_90tank坦克大战项目的学习
CocosCreator项目学习系列<三>坦克大战项目的学习<25/12/2017> 知识点总结: 1.TileMap的使用精髓; 2.Joystick虚拟摇杆的整合单脚本; ...
- unet是残差网络吗_深度学习系列(三)卷积神经网络模型(ResNet、ResNeXt、DenseNet、DenceUnet)...
深度学习系列(三)卷积神经网络模型(ResNet.ResNeXt.DenseNet.Dence Unet) 内容目录 1.ResNet2.ResNeXt3.DenseNet4.Dence Unet 1 ...
- 【Silverlight】Bing Maps学习系列(三):如何控制地图
本篇主要介绍如何对地图的一些常用控制操作,包括地图加载模式.根据精度和纬度定位.变焦程度等. 一.动态设置地图加载模式 在本系列二中介绍了地图加载模式,可以给地图控件设置一种模式的地图加载模式,呈现数 ...
- Java 源码学习系列(三)——Integer
Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...
- C++学习系列(三)—— 泛型编程(STL)
原文链接:https://www.wkeyu.cn/235.html C++提高编程 本阶段主要针对C++泛型编程 和***STL*** 技术做详细学习,学习C++更深层次的使用 代码仓库:https ...
最新文章
- jQuery 属性操作——案例:购物车案例模块
- NYOJ 117 求逆序数
- java chain_java 8中 predicate chain的使用
- 每天一道算法题(39)——含有重复字符的全排列
- DNN: ModuleSettings Vs TabModuleSettings
- 视频号容易被官方封号的违规操作,你中招了吗?
- js对象、数字深拷贝方式(转)
- CPU的设计与实现(2)--逻辑电路设计
- 燕文物流完成上市辅导:董事长周文兴持股30%,曾因丢失邮件被批
- 软件漏洞及缓冲区溢出
- vue 文件.eslintrc.js 配置规则
- 通达OA 2015 8.12版本取消注册功能介绍
- 计算机可以谭音乐吗,谭真家乡类歌曲中的音乐意境分析
- java dump文件怎么生成和分析-JMAP用法
- c语言 tan atan的使用说明
- 全国大学生数学建模竞赛
- 机器学习(十三)——机器学习中的矩阵方法(3)病态矩阵、协同过滤的ALS算法(1)...
- 建筑与计算机技术,建筑与结构设计中计算机技术的应用探析
- IBATIS操作BLOB和CLOB
- vs2010c语言复数i怎么表示,学编程应该知道的c语言中的复数操作