C++开发基础——类对象与构造析构

一、基础概念

类:用户自定义的数据类型。

对象:类类型的变量,类的实例。

类的成员:成员变量和成员函数。

成员变量:类中定义的变量。

成员函数:类中定义的函数。

定义类的代码样例:

class ClassName
{
//members
};
//类定义的右花括号后面必须有分号

类的访问修饰符:public、private、protected。

public: 类的成员可以被类外部的非成员函数访问。

private: 类的成员可以被同一个类中的成员函数访问,或者被友元函数访问,该修饰符可以禁止一些针对类中成员的高风险操作。

protected: 类的成员可以在子类中被访问。

成员函数可以引用同一个类中的所有成员变量,无论它们用哪种修饰符。

class ClassName
{
public://members
private://members
protected://members
};

C++编程中,结构体和类的使用方式几乎完全相同。结构体中的成员,可以是变量,也可以是函数。

与类的成员不同的是,结构体中的成员默认是public修饰的,而类中的成员默认是private修饰的。

访问类成员的方法: 

用类的对象来访问:对象名.成员名

用类的指针来访问:指针名->成员名

关于成员函数的内存空间:

基于同一个类创建的多个对象,该类的成员函数被多个对象所共享,即类的成员函数在多个对象之间只有一个副本。

二,构造函数

1.关于构造函数

        程序在创建对象时,将自动调用构造函数。类的成员变量可以由构造函数来初始化,构造函数与包含它的类同名,没有返回值,也没有返回类型,指定返回类型会导致编译报错。

2.默认构造函数

        如果开发者没有给类指定构造函数,编译器会给类定义一个默认的构造函数去调用,编译器生成的默认构造函数,没有参数,只创建对象,给成员变量赋默认值。

        程序中没有定义任何构造函数时,编译器会提供默认构造函数。

        当程序中已经为一个类提供了非默认构造函数,就必须再定义一个不接受任何传参的默认构造函数。

默认构造函数的定义方式: 

方式一,给已有的构造函数的所有参数提供默认值

Stock(string co = "Error", int n = 0, double price = 0.0)
{
}

方式二,通过函数重载的方式,定义一个没有任何传参的构造函数

Stock() //重载
{company = "no name";shares = 0;share_val = 0.0;total_val = 0.0;
}

基于默认构造函数创建对象的方式:

Stock first;
Stock first = Stock();
Stock *first_ptr = new Stock;

基于非默认构造函数创建对象的方式:

Stock first("food");

注意,调用默认构造函数,通过隐式的方式创建对象时,不要使用圆括号。

Stock second();  //返回Stock对象的函数
Stock second;  //隐式创建对象

3.构造函数的注意事项

1.不需要被显式调用,由系统调用。

2.无返回值,但是不需要用void修饰。

3.函数声明时,用public修饰。

4.对象在被复制时,调用的不是构造函数,是拷贝构造函数。

5.构造函数可以被重载,一个类可以有多个构造函数。

4.构造函数的初始化列表 

写法样例:

Time::Time(int tmphour, int tmpmin, int tmpsec):Hour(tmphour), Minute(tmpmin) //初始化列表
{Second = tmpsec; //函数体中赋初值
}

初始化列表对变量的初始化顺序是按照变量在类中的定义顺序来操作的,先被定义的先初始化。

系统会先执行初始化列表中的初始化操作,再执行函数体中的代码逻辑。因此,可以在初始化列表中初始化成员变量的值,初始化完成后可以在函数体中修改成员变量的值。

特殊情况:const修饰的成员变量,在初始化列表中初始化以后,不能在函数体中再进行赋值操作。

Time::Time(int tmphour, int tmpmin, int tmpsec):Hour(tmphour), Minute(tmpmin), testValue(30)
{testValue = 40; //错误操作,不可以在这里修改testValue的初值
}

5.构造函数初始化对象的方式

1、显式调用构造函数

Stock food = Stock("World Cabbage", 250, 1.25);

2、隐式调用构造函数

Stock garment("Furry Mason", 50, 2.5);  
//这种格式比较紧凑,它与下面的显式调用等价
Stock garment = Stock("Furry Mason", 50, 2.5);

3、创建对象时未提供初始值,系统会调用默认构造函数

Stock fluffy;

4、构造函数与new一起使用

Stock *pstock = new Stock("Electroshock Games", 18, 19.5);

该语句创建一个Stock对象,并将该对象的地址赋值给pstock指针。在这种情况下,对象没有名称,但可以使用指针来管理该对象。

5、特殊情况,只有一个参数的构造函数,容易发生隐式的类型转换

如果构造函数只有一个参数,则将对象初始化为一个与参数的类型相同的值时,该构造函数将被调用。

例如,构造函数原型:

Bozo::Bozo(int num)
{Num = num;
}

则可以使用下面的任何一种方式来初始化该对象:

Bozo A_obj = Bozo(44);
Bozo B_obj(66);
Bozo C_obj = 32;  //可以使用explicit关键字来关闭这种特性。

6.C++11风格的对象初始化

C++11中可以用{ }来进行对象的初始化:

Stock hot_tip = {"Derivatives Plus Plus", 100, 45.0};
Stock jock {"Sport Age Storage, Inc"};
Stock temp {};

三,析构函数

1.关于析构函数

类的析构函数总是在释放对象时自动调用。

如果构造函数中使用new来分配内存,则析构函数中必须使用delete来释放这些内存。

在栈内存中先后创建两个对象,最晚创建的对象将最先调用析构来删除,最早创建的对象将最后调用析构来删除。

2.析构函数的注意事项

1.不需要被显式调用,由系统调用。

2.无返回值,但是不需要用void修饰。

3.函数声明时,用public修饰。

4.析构函数没有函数参数,不能被重载,所以一个类只能有一个析构函数。

5.如果开发者在构造函数里面new了一段内存,此时需要自定义一个析构函数,并在析构函数中调用delete方法将这段内存释放掉。

对于指针类型的成员变量,在考虑析构问题时,有两个编程技巧:

忘记使用delete释放对象——使用智能指针std::unique_ptr进行封装。

不知道什么时候释放由多个对象指向或使用的同一个对象——使用智能指针std::shared_ptr进行封装。

四,创建对象:堆内存 & 栈内存

 如果对象只在一个函数中被使用,且该对象被使用的时间很短,并且从创建该对象的函数return后不再需要该对象,推荐在栈内存中创建该对象。

如果对象必须在多个函数之间使用,且该对象被使用的时间很长,推荐在堆内存中创建该对象。

栈内存中创建对象的语法:

<ClassName> <object name>;

代码样例:

Rectangle obj;

堆内存中创建对象的语法:

<ClassName> *<object name>  =  new <ClassName>;

代码样例:

Rectangle *obj = new Rectangle();

五,const对象 & const成员函数

1.const对象

const对象的所有成员变量都是const类型,不能被修改。

当通过const指针或const引用访问对象时,具有与直接访问const对象相同的限制。

对于const对象,只能调用const成员函数。

const修饰的成员函数,就是在告诉开发者,该const对象的哪些成员函数可以被调用。一般只对getter函数用const修饰,对setter函数用const修饰会导致编译报错。

2.const成员函数

只要类的成员函数不修改对象的成员变量,就应该将其声明为const。

代码样例:

void Stock::show() const    //const放函数名后面

3.mutable关键字

const对象中,被mutable关键字修饰的成员变量仍可以被修改,且可以同时被const成员函数和非const成员函数所修改。

class Screen{
public:void some_member() const;
private:mutable size_t access_ctr;  //在const对象内也能被修改
};void Screen::some_member() const
{++access_ctr;  //保存一个计数值,用于记录成员函数被调用的次数
}

六,成员函数的this指针

    this是当前对象的地址。

    返回对象本身需要进行解引用操作,即return *this,返回的是调用该成员函数的对象。

    成员函数通过this指针来访问调用它的整个对象,而不是直接访问对象的某个成员。

    正常情况下,this的类型是指向对象的常指针,const成员函数相当于把this声明为指向不可变对象的常指针。

    return this的函数返回值:返回值是对象 & 返回值是对象的引用。

    返回值是对象:改变的是同一个对象。

    返回值是对象的引用:改变的不是同一个对象,而是对象的副本。

代码样例,假设有一个对象myBox:

class Box
{
private:double length {1.0};double width {1.0};double height {1.0};
public:...
}Box myBox{3.0, 4.0, 5.0};

场景1:返回值是对象

成员函数:

Box* Box::setLength(double lv)
{if(lv > 0){length = lv;}return this;
}Box* Box::setWidth(double wv)
{if(wv > 0){width = wv;}return this;
}Box* Box::setHeight(double hv)
{if(hv > 0){height = hv;}return this;
}

要修改同一个对象的所有成员变量,调用方法: 

myBox.setLength(20.0)->setWidth(30.0)->setHeight(40.0);
//Set all dimensions of myBox

场景2:返回值是对象的引用

成员函数:

Box& Box::setLength(double lv)
{if(lv > 0){length = lv;}return *this;
}Box& Box::setWidth(double wv)
{if(wv > 0){width = wv;}return *this;
}Box& Box::setHeight(double hv)
{if(hv > 0){height = hv;}return *this;
}

要修改同一个对象的所有成员变量,调用方法:

myBox.setLength(20.0).setWidth(30.0).setHeight(40.0);
//Set all dimensions of myBox

七,关于对象的动态内存分配

1.如果对象是动态变量,则当执行完定义该对象的代码块时,就会调用该对象的析构函数。

2.如果对象是静态变量,则在整个程序运行结束时,才调用该对象的析构函数。

3.如果对象是用new创建的,则仅当显式调用delete删除对象时,才调用该对象的析构函数。

具体的区别参考《c++ primer plus》的这张图

八,对象的生命周期

1.对象的生命周期——创建对象

以下操作会创建对象:

1.在栈内存中声明对象。

2.使用new、new[]显式分配空间。

3.使用智能指针显式分配空间。

*特殊情况,创建对象的同时,创建一个内嵌的对象

#include <string>
class MyClass
{
private:std::string mName;
};int main()
{MyClass obj;return 0;
}

基于MyClass类创建obj对象的时候,同时会创建一个内嵌的string对象,当包含string对象的obj对象被销毁时,string对象也被一起销毁。

2.对象的生命周期——销毁对象

销毁对象时,系统会进行的操作:调用对象的析构函数,释放对象占用的内存。

析构函数中的常见操作:释放动态分配的内存、关闭文件句柄。

对象的析构顺序与声明对象时的初始化顺序相反,最先被初始化的对象,最后被析构。

栈内存中的对象销毁:

当栈内存中的对象超出作用域以后,对象会被自动销毁。

对于一段代码,当代码遇到结束时的大括号时,这个大括号内所有创建在栈内存中的对象会被自动销毁。

例如,以下代码中,对象是创建在栈内存中的,会自动销毁。

int main()
{MyClass myCell("a");...return 0;
} //myCell is destroyed as this block ends.

堆内存中的对象销毁:

如果没有使用智能指针,在堆内存中创建的对象,不会被自动销毁。

必须调用delete或delete[]删除对象指针,从而调用析构函数释放内存。

例如,以下代码中,对象是创建在堆内存中的,不会自动销毁。

int main()
{MyClass* objPtr1 = new MyClass("b");MyClass* objPtr2 = new MyClass("c");...delete objPtr1;objPtr1 = nullptr;return 0;
} //objPtr2 is not destroyed.

九,类的静态成员

1.静态成员变量

    当类的成员变量被声明为static类型时,该变量被称为类的静态成员变量。

    类的静态成员变量作用于整个类,独立于任何类的对象。该类的所有对象都可以访问这个静态成员变量。

    静态成员变量可以作为类的特殊全局变量,它可以用来存储关于类的具体信息,比如当前类有多少个对象等。

    该类即使没有被实例化为对象,它的静态成员变量依然存在。

    静态成员变量,在多个类对象之间共享访问,只定义一次。

    在创建对象时,对象的普通成员变量会在每个对象中拷贝一个独立的副本。如果对象的某个成员变量的值是个常量,则创建多个对象还得为这个常量生成多个副本,很浪费内存空间,如果将该成员变量声明为静态成员变量,则该成员变量会被多个对象所共享,且在创建很多对象的期间只有一个实例,不会产生多个副本。

2.静态成员函数

    当类的成员函数被声明为static类型时,该函数被称为类的静态成员函数。

    类的静态成员函数也作用于整个类,独立于任何类的对象,该类的所有对象都可以调用这个静态成员函数。

    注意,由于静态成员函数与具体的对象无关,所以静态成员函数不能用const修饰,也不能使用this指针。

    如果静态成员函数被声明为public,还可以在类的外部被调用。

十,参考阅读

《C++高级编程》

《C++17入门经典》

《C++新经典》

《C++ Primer》

《C++ Primer Plus》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/278718.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式学习第二十九天!(数据结构的概念、单向链表)

数据结构&#xff1a; 1. 定义&#xff1a; 一组用来保存一种或者多种特定关系的数据的集合&#xff08;组织和存储数据&#xff09; 1. 程序设计&#xff1a; 将现实中大量而复杂的问题以特定的数据类型和特定的数据结构存储在内存中&#xff0c;并在此基础上实现某个特定的功…

【排序】快速排序

原理 对于一个数组x&#xff0c;快速排序流程如下&#xff1a; 确定分界点a&#xff0c;可以取x[l]、x[r]、x[l r / 2]、随机&#xff08;四种都可以&#xff09;调整区间&#xff0c;使得&#xff1a;区间被分成 < a 和 > a的两部分&#xff0c;左边 < a&#xff…

Jenkins-pipeline流水线构建完钉钉通知

添加钉钉机器人 在钉钉群设置里添加机器人拿出Webhook地址&#xff0c;设置关键词 Jenkins安装钉钉插件 Dashboard > 系统管理 > 插件管理&#xff0c;搜索构建通知&#xff0c;直接搜索Ding Talk也行 安装DingTalk插件&#xff0c;重启Jenkins 来到Dashboard > 系…

【物联网应用】基于云计算的智能化温室种植一体化平台

目录 第一章 作品概述 1.1. 作品名称 1.2. 应用领域 1.3.主要功能 1.4.创新性说明 第二章 需求分析 2.1 现实背景 2.2 用户群体及系统功能 2.3 竞品分析 第三章 技术方案 3.1. 硬件组成与来源 3.2. 硬件设计合理性 3.3. 硬件系统设计图 3.4. 接口的通用性与可扩展性 3.5. 代码规…

【ARM】DSTREAM上面的各个指示灯代表什么意思?

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 对于DStream仿真器上面的指示灯亮灭代表的意义进行分析。 2、 问题场景 主要对于DStream仿真器的使用过程中&#xff0c;不同的情况下面仿真器的指示灯会进行相应的亮灭。了解一下不同指示灯的亮灭所提示的信息…

注册个人小程序

访问地址 https://mp.weixin.qq.com/ 立即注册 选择小程序 注册 填写信息 登录邮箱 访问邮箱的链接激活账号 选择个人&#xff0c;填写信息 注册完成&#xff0c;即可登录进入填写信息

idea 开发serlvet班级通讯录管理系统idea开发mysql数据库web结构计算机java编程layUI框架开发

一、源码特点 idea开发 java servlet 班级通讯录管理系统是一套完善的web设计系统mysql数据库 系统采用serlvetdaobean mvc 模式开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 servlet 班…

【iOS】——Blocks

文章目录 前言一、Blocks概要1.什么是Blocks 二、Block模式1.block语法2.block类型变量3.截获自动变量值4._Block修饰符5.截获的自动变量 三、Blocks的实现1.Block的实质2.截获自动变量值3._Block说明符4.Block存储域 前言 一、Blocks概要 1.什么是Blocks Blocks是C语言的扩…

使用jenkins-pipeline进行利用项目文件自动化部署到k8s上

Discard old builds:丢弃旧的构建,目的是管理存储空间、提升性能以及保持环境整洁 Do not allow concurrent builds: 禁止并发构建是指同一时间内只允许一个构建任务执行,避免多个构建同时运行可能带来的问题 Do not allow the pipeline to resume if the controller resta…

DockerHub搜索并拉取一个Redis镜像

1&#xff09;去DockerHub搜索Redis镜像 2&#xff09;查看Redis镜像的名称和版本 3&#xff09;利用docker pull命令拉取镜像 4&#xff09;利用docker save命令将 redis:latest打包为一个redis.tar包 5&#xff09;利用docker rmi 删除本地的redis:latest 6&#xff09;利用…

Flutter-自定义图片3D画廊

效果 需求 3D画廊效果 设计内容 StackGestureDetectorTransformPositioned数学三角函数 代码实现 具体代码大概300行 import dart:math;import package:flutter/material.dart; import package:flutter_xy/widgets/xy_app_bar.dart;import ../../r.dart;class ImageSwitc…

zookeeper集群安装部署和集群异常处理

准备jdk和zookeeper安装包【官网即可下载】 zookeeper-3.5.1-alpha.tar.gz jdk1.7.0_8020200612.tar 准备三台linux虚拟机【具体以项目实际需要为准】&#xff0c;并安装jdk和zookeeper 虚拟机地址如下&#xff1a;194.1.1.86&#xff08;server.1&#xff09;、194.1.1.74…

Lyricsx让歌词悬浮于最顶层

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Lyricsx让歌词悬浮于最顶层 前言Lyricsx的特色功能&#xff1a;歌词展现的新高度安装在 macOS 上安装 Lyricsx&#xff1a; 前言 在音符的世界里&#xff0c;歌词是一把打开心扉的钥匙&#xff0c;而…

全国各省市县统计年鉴/中国环境统计年鉴/中国工业企业数据库/中国专利数据库/污染排放数据库

统计年鉴是指以统计图表和分析说明为主&#xff0c;通过高度密集的统计数据来全面、系统、连续地记录年度经济、社会等各方面发展情况的大型工具书来获取统计数据资料。 统计年鉴是进行各项经济、社会研究的必要前提。而借助于统计年鉴&#xff0c;则是研究者常用的途径。目前国…

蓝桥之手撕排序算法——冒泡、选择、插入、快排、归并(Python版)

目录 1. 排序引言 2. 冒泡排序 2.1 算法思想 2.2 代码实现 2.3 时空复杂度分析 3. 选择排序 3.1 算法思想 3.2 代码实现 3.3 时空复杂度分析 4. 插入排序 4.1 算法思想 4.3 代码实现 4.4 时空复杂度分析 5. 快速排序 5.1 算法思想 5.2 代码实现 5.3 时空复杂度分…

考研C语言复习进阶(5)

目录 1. 为什么使用文件 2. 什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3. 文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 4. 文件的顺序读写 ​编辑 ​编辑 4.1 对比一组函数&#xff1a; ​编辑 5. 文件的随机读写 5.1 fseek 5.2 ftell 5.3 rewind…

深度学习实战模拟——softmax回归(图像识别并分类)

目录 1、数据集&#xff1a; 2、完整代码 1、数据集&#xff1a; 1.1 Fashion-MNIST是一个服装分类数据集&#xff0c;由10个类别的图像组成&#xff0c;分别为t-shirt&#xff08;T恤&#xff09;、trouser&#xff08;裤子&#xff09;、pullover&#xff08;套衫&#xf…

论文笔记:Llama 2: Open Foundation and Fine-Tuned Chat Models

导语 Llama 2 是之前广受欢迎的开源大型语言模型 LLaMA 的新版本&#xff0c;该模型已公开发布&#xff0c;可用于研究和商业用途。本文记录了阅读该论文的一些关键笔记。 链接&#xff1a;https://arxiv.org/abs/2307.09288 1 引言 大型语言模型&#xff08;LLMs&#xff…

深入探索C与C++的混合编程

实现混合编程的技术细节 混合使用C和C可能由多种原因驱动。一方面&#xff0c;现有的大量优秀C语言库为特定任务提供了高效的解决方案&#xff0c;将这些库直接应用于C项目中可以节省大量的开发时间和成本。另一方面&#xff0c;C的高级特性如类、模板和异常处理等&#xff0c;…

ONLYOFFICE文档8.0全新发布:私有部署、卓越安全的协同办公解决方案

ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案 文章目录 ONLYOFFICE文档8.0全新发布&#xff1a;私有部署、卓越安全的协同办公解决方案摘要&#x1f4d1;引言 &#x1f31f;正文&#x1f4da;一、ONLYOFFICE文档概述 &#x1f4ca;二、ONLYOFFI…