C++学习笔记----7、使用类与对象获得高性能(一)---- 书写类(2)

news/2024/12/22 16:24:42/

2.2、定义成员函数

        前面对SpreadsheetCell类的定义足以让你生成类的对象。然而,如果想调用setValue()或者getValue()成员函数,连接器就会抱怨这些函数没有定义。这是因为到目前为止,这些成员函数只有原型,而还没有实现。通常,类的定义会在模块接口文件。对于成员函数的定义,你有一个选择:可以在模块定义文件或者在模块实现文件。

下面是SpreadsheetCell类,在类内对成员函数进行了实现:

export module spreadsheet_cell;
export class SpreadsheetCell
{
public:void setValue(double value) { m_value = value; }double getValue() const { return m_value; }
private:double m_value{ 0 };
};

        与头文件不同,c++模块中把成员函数定义放在模块接口文件中并没有什么不好。这个我们以后再讨论。然而,我们还是通常把成员函数定义放在模块实现文件中,是为了保证模块接口干净,不需要实现细节。

        模块实现的第一行指出该实现是哪个模块。下面是spreadsheet_cell模块中SpreadsheetCell类的两个成员函数的定义:

module spreadsheet_cell;void SpreadsheetCell::setValue(double value)
{m_value = value;
}double SpreadsheetCell::getValue() const
{return m_value;
}

        注意类名之后两个冒号后跟着的是每个成员函数的名字:

void SpreadsheetCell::setValue(double value)

        ::被叫做范围解析操作符。具体内容就是,语法告诉编译器接下来对setValue()成员函数的定义是SpreadsheetCell类的一部分。也要注意,当你定义成员函数时,不需要重复访问说明。

2.2.1、访问数据成员

        对于像setValue()与getValue()这样类的非静态成员函数总是哇规定类的特定对象执行。在成员函数体内,拥有所有对象的类的数据成员的访问权限。对于前面对setValue()的定义,下面这行代码不管什么样的对象调用了成员函数都会改变m_value变量的值:

m_value = value;

        如果setValue()被两个不同的对象调用,同样的代码行(每个对象执行一次)在两个不同的对象中改变了变量值。

2.2.2、调用其他成员函数

        可以在另外一个成员函数中调用一个类的成员函数。例如,考虑对SpreadsheetCell类进行扩展,允许使用字符串或者数字来设置和访问格子的值。当你尝试将格子的值用字符串来设置时,格子尝试将字符串转化为数字。如果字符串无法转化为一个合法的数字,格子值会忽略。在程序中,无法转化为数字的字符串会为格子生成一个0值。下面是对SpreadsheetCell的类定义:

export module spreadsheet_cell;
import std;export class SpreadsheetCell
{
public:void setValue(double value);double getValue() const;void setString(std::string_view value);std::string getString() const;private:std::string doubleToString(double value) const;double stringToDouble(std::string_view value) const;double m_value{ 0 };
};

        这一版的类只保存了一个double数据。如果客户将数据设置为字符串,会将其转化为double。如果字符串不是合法的数字,double值会被设置为0。类定义显示了两个新的成员函数来设置与访问格子中的文本表达,两个新的内部的辅助成员函数将double转化为字符串以及反向转化。下面是对所有这些成员函数的实现:

module spreadsheet_cell;
import std;
using namespace std;void SpreadsheetCell::setValue(double value)
{m_value = value;
}double SpreadsheetCell::getValue() const
{return m_value;
}void SpreadsheetCell::setString(string_view value)
{m_value = stringToDouble(value);
}string SpreadsheetCell::getString() const
{return doubleToString(m_value);
}string SpreadsheetCell::doubleToString(double value) const
{return to_string(value);
}double SpreadsheetCell::stringToDouble(string_view value) const
{double number{ 0 };from_chars(value.data(), value.data() + value.size(), number);return number;
}

        std::to_string()与from_chars()函数我们以前解释过,这里就不过多阐述了。

        注意这里对doubleToString()成员函数的实现,例如6.1会被转化成6.100000。然而,因为它是一个内部辅助成员函数,可以不必修改任何客户端代码的情况下自由修改其实现。

2.3、使用对象

        前面对类SpreadsheetCell的定义,包含了一个数据成员,四个公共的成员函数,两个内部成员函数。然而,类定义没有产生任何实际的SpreadsheetCell;它只是指出其形状与行为。在这个层面,一个类就像一个架构蓝图。蓝图指出房子应该盖成什么样,但是画出蓝图并没有建造任何房子。房子一定要基于蓝图之后建造。

        同样的,在C++中,可以通过声明一个SpreadsheetCell类型的变量从SpreadsheetCell类定义中构造一个SpreadsheetCell对象。正像建筑工人可以基于给定的蓝图建造多个房子,程序员也可以从SpreadsheetCell类生成多个SpreadsheetCell对象。有两种生成和使用对象的方式:在栈上和在自由分配空间上。

2.3.1、栈上对象

        下面是一些栈上生成和使用SpreadsheetCell对象的例子:

import spreadsheet_cell;
import std;
using namespace std;int main()
{SpreadsheetCell myCell, anotherCell;myCell.setValue(6);anotherCell.setString("3.2");println("cell 1: {}", myCell.getValue());println("cell 2: {}", anotherCell.getValue());println("cell 1: {}", myCell.getString());println("cell 2: {}", anotherCell.getString());
}

就像声明简单变量一样生成对象,除了变量类型就是类名字之外。myCell.setValue(6)代码行中的.被叫做“点”操作符,也叫做成员访问操作符;允许调用对象的公共成员函数。任何类中的公共的数据成员,都可以使用点操作符来访问。记住我们并不推荐将成员变量设置为可以公共访问。

程序的输出如下:

cell 1: 6
cell 2: 3.2
cell 1: 6.000000
cell 2: 3.200000

2.3.2、自由分配空间上的对象

        也可以使用new来动态分配对象:

import spreadsheet_cell;
import std;using namespace std;int main()
{SpreadsheetCell* myCellp{ new SpreadsheetCell{ } };myCellp->setValue(3.7);println("cell 1: {} {}", myCellp->getValue(), myCellp->getString());delete myCellp;myCellp = nullptr;
}

        当在自由分配空间上生成一个对象时,可以通过“箭头”操作符->来访问成员。箭头包含了间接引用(*)和成员访问(.)。也我可能要用这两个操作符,但是这样做的话从风格上来看就有点尴尬:

import spreadsheet_cell;
import std;using namespace std;int main()
{SpreadsheetCell* myCellp{ new SpreadsheetCell{ } };(*myCellp).setValue(3.7);println("cell 1: {} {}", (*myCellp).getValue(), (*myCellp).getString());delete myCellp;myCellp = nullptr;
}

        就像你要释放分配在自由分配空间上其他内存一样,也必须通过调用delete来释放分配在自由分配空间上的对象的内存,就像上面的代码那样!为了保证安全,避免问题,你真的应该使用智能指针,举例如下:

import spreadsheet_cell;
import std;using namespace std;int main()
{auto myCellp{ make_unique<SpreadsheetCell>() };// Equivalent to:// unique_ptr<SpreadsheetCell> myCellp{ new SpreadsheetCell{ } };myCellp->setValue(3.7);println("cell 1: {} {}", myCellp->getValue(), myCellp->getString());
}

        使用智能指针就不需要手动释放内存了,它会自动释放。

        当使用new分配对象空间时,使用完毕之后要用delete进行释放,或者,最好使用智能指针来自动管理内存!

        如果不使用智能指针的话,将删除其指向的对象之后设置为nullptr不失为一个好主意。我们并不要求你这么做,如果在删除之后指针被意外使用到的话,也会很容易排错。


http://www.ppmy.cn/news/1526563.html

相关文章

根据NVeloDocx Word模板引擎生成Word(三)

基于永久免费开放的《E6低代码开发平台》的Word模版引擎NVeloDocx&#xff0c;实现根据Word模版生成Word文件&#xff0c;前面2篇已经非常详细介绍了《主表单字段》&#xff0c;《子表记录循环输入到表格》。那这一篇我们就介绍插入单张图片、二维码&#xff0c;条形码等等&…

Android Tools | 如何使用Draw.io助力Android开发:从UI设计到流程优化

Android Tools | 如何使用Draw.io助力Android开发&#xff1a;从UI设计到流程优化 1. 引言 在Android开发中&#xff0c;视觉化设计与流程管理至关重要。虽然开发工具如Android Studio强大&#xff0c;但它并不适用于所有设计场景。Draw.io是一款免费的在线绘图工具&#xff…

opencv之傅里叶变换

文章目录 前言理论基础Numpy实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 高通滤波示例OpenCV实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 低通滤波示例 前言 图像处理一般分为空间域处理和频率域处理。 空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰…

设计模式 -- 单例设计模式

1.1 单例 创建一个单例对象 SingleModel , SingleModel 类有它的私有构造函数和本身的一个静态实例。 SingleModel 类提供了一个静态方法&#xff0c;供外界获取它的静态实例。 DesignTest 我们的演示类使用 SingleModel 类来获取 SingleModel 对象。 创建 Single…

基于YOLO深度学习和百度AI接口的手势识别与控制项目

基于YOLO深度学习和百度AI接口的手势识别与控制项目 项目描述 本项目旨在开发一个手势识别与控制系统&#xff0c;该系统能够通过摄像头捕捉用户的手势&#xff0c;并通过YOLO深度学习模型或调用百度AI接口进行手势识别。识别到的手势可以用来控制计算机界面的操作&#xff0…

数据结构(Day13)

一、学习内容 内存空间划分 1、一个进程启动后&#xff0c;计算机会给该进程分配4G的虚拟内存 2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】 3、3G-4G是内核空间【与底层驱动有关】 4、所有进程共享3G-4G的内核空间&#xff0c;每个进程独立拥有0G-3G的用户空间 …

vmware Vnet8虚拟网卡丢失的找回问题

vmware Vnet8虚拟网卡丢失的找回问题 1.打开VMware Workstation 2.然后点击Edit --> Virtual Network Edit --> 打开Virtual Network Edit框 &#xff0c; 3.点击最下面的的Restore Default 按钮&#xff0c; 3.恢复默认设置&#xff0c;这会在网络连接那块可以看到丢失…

Python [ GUI编程自学 ],虽然但是,还是想出一个系列

本文主要介绍了GUI组件的其他常用组件部分&#xff1a;optionmenu选项菜单&#xff0c;scale滑块&#xff1b;颜色框、文件选择框&#xff0c;读取文件内容&#xff1b;简单对话框、通用消息、ttk子模块问题&#xff1b; 一系列GUI编程&#xff0c;有相关的专栏&#xff0c;欢迎…