The this Pointer (this 指针) and An Array of Objects (对象数组)

The this Pointer [this 指针] and An Array of Objects [对象数组]

  • 1. The `this` Pointer (`this` 指针)
  • 2. An Array of Objects (对象数组)
  • References

1. The this Pointer (this 指针)

class Stock {
private:
	double total_val_;
	...
public:
	double Total() const { return total_val_; }
	...
};

That is, you can use the Total() method to obtain the value, but the class doesn’t provide a method for specifically resetting the value of total_val_.
可以使用方法 Total() 来获得 total_val_ 的值,但这个类没有提供专门用于重新设置 total_val_ 的值的方法。

const Stock & Stock::TopVal(const Stock & stock) const {
	if (stock.total_val_ > total_val_) {
		return stock;  // argument object
	}
	else {
		return *this;  // invoking object
	}
}

The most direct way is to have the method return a reference to the object that has the larger total value.
最直接的方法是让方法返回一个引用,该引用指向 total_val_ 较高的对象。

This function accesses one object implicitly and one object explicitly, and it returns a reference to one of those two objects. The const in parentheses states that the function won’t modify the explicitly accessed object, and the const that follows the parentheses states that the function won’t modify the implicitly accessed object. Because the function returns a reference to one of the two const objects, the return type also has to be a const reference.
该函数隐式地访问一个对象,而显式地访问另一个对象,并返回其中一个对象的引用。括号中的 const 表明,该函数不会修改被显式地访问的对象;而括号后的 const 表明,该函数不会修改被隐式地访问的对象。由于该函数返回了两个 const 对象之一的引用,因此返回类型也应为 const 引用。

top = stock1.TopVal(stock2);
top = stock2.TopVal(stock1);

The first form accesses stock1 implicitly and stock2 explicitly, whereas the second accesses stock1 explicitly and stock2 implicitly. Either way, the method compares the two objects and returns a reference to the one with the higher total value.
第一种格式隐式地访问 stock1,而显式地访问 stock2;第二种格式显式地访问 stock1,而隐式地访问 stock2无论使用哪一种方式,都将对这两个对象进行比较,并返回 total_val_ 较高的那一个对象。

The fact that the return type is a reference means that the returned object is the invoking object itself rather than a copy passed by the return mechanism.
返回类型为引用意味着返回的是调用对象本身,而不是其副本。

在这里插入图片描述

Here stock.total_val_ is the total value for the object passed as an argument, and total_val_ is the total value for the object to which the message is sent. If stock.total_val_ is greater than total_val_, the function returns a reference to stock. Otherwise, it returns a reference to the object used to evoke the method. In OOP talk, that is the object to which the total_val_ message is sent. If you make the call stock1.TopVal(stock2), then stock is a reference for stock2 (that is, an alias for stock2), but there is no alias for stock1.
stock.total_val_ 是作为参数传递的对象的总值,total_val_ 是用来调用该方法的对象的总值。如果 stock.total_val_ 大于 total_val_,则函数将返回指向 stock 的引用;否则,将返回用来调用该方法的对象。在 OOP 中,是 total_val_ 消息要发送给的对象。如果调用 stock1.TopVal(stock2),则 stockstock2 的引用 (即 stock2 的别名),但 stock1 没有别名。

evoke [ɪˈvəʊk]:vt. 唤起,引起 (感情、记忆或形象)

The this pointer points to the object used to invoke a member function. Basically, this is passed as a hidden argument to the method. Thus, the function call stock1.TopVal(stock2) sets this to the address of the stock1 object and makes that pointer available to the TopVal() method. Similarly, the function call stock2.TopVal(stock1) sets this to the address of the stock2 object. In general, all class methods have a this pointer set to the address of the object that invokes the method. Indeed, total_val_ in TopVal() is just shorthand notation for this->total_val_ .
this 指针指向用来调用成员函数的对象,this 被作为隐藏参数传递给方法。这样,函数调用 stock1.TopVal(stock2)this 设置为 stock1 对象的地址,使得这个指针可用于 TopVal() 方法。同样,函数调用 stock2.TopVal(stock1)this 设置为 stock2 对象的地址。一般来说,所有的类方法都将 this 指针设置为调用它的对象的地址。确实,TopVal() 中的 total_val_ 只不过是 this->total_val_ 的简写。

在这里插入图片描述

Each member function, including constructors and destructors, has a this pointer. The special property of the this pointer is that it points to the invoking object. If a method needs to refer to the invoking object as a whole, it can use the expression *this. Using the const qualifier after the function argument parentheses qualifies this as being a pointer to const; in that case, you can’t use this to change the object’s value.
每个成员函数 (包括构造函数和析构函数) 都有一个 this 指针。this 指针指向调用对象。如果方法需要引用整个调用对象,则可以使用表达式 *this在函数的括号后面使用 const 限定符将 this 限定为 const,这样将不能使用 this 来修改对象的值。

What you want to return, however, is not this because this is the address of the object.You want to return the object itself, and that is symbolized by *this. Recall that applying the dereferencing operator * to a pointer yields the value to which the pointer points. Now you can complete the method definition by using *this as an alias for the invoking object.
要返回的并不是 this,因为 this 是对象的地址,而是对象本身,即 *this。将解除引用运算符 * 用于指针,将得到指针指向的值。现在,可以将 *this 作为调用对象的别名来完成前面的方法定义。

  • stock.h
#ifndef STOCK_H_
#define STOCK_H_

#include <string>

// class declaration
class Stock {
private:
	std::string company_;
	int shares_;
	double share_val_;
	double total_val_;

	void SetTot() { total_val_ = shares_ * share_val_; }
public:
	Stock();  // Default constructor
	Stock(const std::string &company, const long num = 0, const double price = 0.0);

	~Stock();

	void Buy(const long num, const double price);
	void Sell(const long num, const double price);
	void Update(const double price);
	void Show()const;

	const Stock &TopVal(const Stock &stock) const;
}; // Note semicolon at the end

#endif

  • stock.cpp
#include <iostream>

#include "stock.h"

// Default constructor
Stock::Stock() {
	std::cout << "Stock::Stock()" << "\n";
	company_ = "default name";
	shares_ = 0;
	share_val_ = 0.0;
	total_val_ = 0.0;
}

Stock::Stock(const std::string &company, const long num, const double price) {
	std::cout << "Stock::Stock(const std::string &company, const long num = 0, const double price = 0.0): " << company << "\n";
	company_ = company;
	if (num < 0) {
		std::cout << "Number of shares_ can't be negative; " << company_ << " shares_ set to 0.\n";
		shares_ = 0;
	}
	else {
		shares_ = num;
	}

	share_val_ = price;

	SetTot();
}

// Destructor
Stock::~Stock() {
	std::cout << "Stock::~Stock(): " << company_ << "\n";
}

void Stock::Buy(const long num, const double price) {
	if (num < 0) {
		std::cout << "Number of shares_ purchased can't be negative. " << "Transaction is aborted.\n";
	}
	else {
		shares_ += num;
		share_val_ = price;
		SetTot();
	}
}

void Stock::Sell(const long num, const double price) {
	if (num < 0) {
		std::cout << "Number of shares_ sold can't be negative. " << "Transaction is aborted.\n";
	}
	else if (num > shares_) {
		std::cout << "You can't sell more than you have! " << "Transaction is aborted.\n";
	}
	else {
		shares_ -= num;
		share_val_ = price;
		SetTot();
	}
}

void Stock::Update(const double price) {
	share_val_ = price;
	SetTot();
}

void Stock::Show() const {
	// set format to #.###
	std::ios_base::fmtflags original = std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::streamsize precision = std::cout.precision(3);

	std::cout << "Company: " << company_ << "\n  Shares = " << shares_;
	std::cout << "  Share Price = $" << share_val_;

	// set format to #.##
	std::cout.precision(2);
	std::cout << "  Total Worth = $" << total_val_ << '\n';

	// restore original format
	std::cout.setf(original, std::ios_base::floatfield);
	std::cout.precision(precision);
}

const Stock & Stock::TopVal(const Stock & stock) const {
	if (stock.total_val_ > total_val_) {
		return stock;  // argument object
	}
	else {
		return *this;  // invoking object
	}
}

2. An Array of Objects (对象数组)

You declare an array of objects the same way you declare an array of any of the standard types.
声明对象数组的方法与声明标准类型数组相同。

Stock yongqiang[4];  // creates an array of 4 Stock objects

Recall that a program always calls the default class constructor when it creates class objects that aren’t explicitly initialized. This declaration requires either that the class explicitly define no constructors at all, in which case the implicit do-nothing default constructor is used, or, as in this case, that an explicit default constructor be defined. Each element - yongqiang[0], yongqiang[1], and so on - is a Stock object and thus can be used with the Stock methods.
当程序创建未被显式初始化的类对象时,总是调用默认构造函数。上述声明要求,这个类要么没有显式地定义任何构造函数 (在这种情况下,将使用不执行任何操作的隐式默认构造函数),要么定义了一个显式默认构造函数。每个元素 (yongqiang[0]yongqiang[1] 等) 都是 Stock 对象,可以使用 Stock 方法。

yongqiang[0].Update();  // apply Update() to 1st element
yongqiang[3].Show();  // apply Show() to 4th element

const Stock * top = yongqiang[2].TopVal(yongqiang[1]);
// compare 3rd and 2nd elements and set top to point at the one with a higher total value

You can use a constructor to initialize the array elements. In that case, you have to call the constructor for each individual element.
可以用构造函数来初始化数组元素。在这种情况下,必须为每个元素调用构造函数。

const int NUM = 4;
Stock stocks[NUM] = {
	Stock("first", 12.5, 20),
	Stock("second", 200, 2.0),
	Stock("third", 130, 3.25),
	Stock("fourth", 60, 6.5)
};

Here the code uses the standard form for initializing an array: a comma-separated list of values enclosed in braces. In this case, a call to the constructor method represents each value. If the class has more than one constructor, you can use different constructors for different elements.
这里的代码使用标准格式对数组进行初始化:用括号括起的、以逗号分隔的值列表。其中,每次构造函数调用表示一个值。如果类包含多个构造函数,则可以对不同的元素使用不同的构造函数。

const int NUM = 10;
Stock stocks[NUM] = {
	Stock("first", 12.5, 20),
	Stock(),
	Stock("second", 130, 3.25),
};

This initializes stocks[0] and stocks[2] using the Stock(const std::string &company, const long num = 0, const double price = 0.0); constructor as well as stocks[1] using the Stock(); constructor. Because this declaration only partially initializes the array, the remaining seven members are initialized using the default constructor.
上述代码使用 Stock(const std::string &company, const long num = 0, const double price = 0.0); 初始化 stocks[0] and stocks[2],使用构造函数 Stock(); 初始化 stock[1]。由于该声明只初始化了数组的部分元素,因此余下的 7 个元素将使用默认构造函数进行初始化。

初始化对象数组的方案是:首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。因此,要创建类对象数组,则这个类必须有默认构造函数。

Because const Stock &TopVal(const Stock &stock) const; examines just two objects at a time, the program uses a for loop to examine the whole array. Also it uses a pointer-to-Stock to keep track of which element has the highest value.
由于 const Stock &TopVal(const Stock &stock) const; 每次只检查两个对象,因此程序使用 for 循环来检查整个数组。另外,它使用 const Stock * top 指针来跟踪值最高的元素。

  • sample.cpp
#include <iostream>

#include "stock.h"

const int NUM = 4;

int main() {

	{
		// Create an array of initialized objects
		Stock stocks[NUM] = {
			Stock("first", 12, 20.0),
			Stock("second", 200, 2.0),
			Stock("third", 130, 3.25),
			Stock("fourth", 60, 6.5)
		};

		std::cout << "\nStock holdings:\n";
		for (int n = 0; n < NUM; ++n) {
			stocks[n].Show();
		}

		// Set pointer to first element
		const Stock * top = &(stocks[0]);
		for (int n = 1; n < NUM; ++n) {
			top = &top->TopVal(stocks[n]);
		}

		// Now top points to the most valuable holding
		std::cout << "\nMost valuable holding:\n";
		top->Show();
	}

	return 0;
}

在这里插入图片描述

Stock::Stock(const std::string &company, const long num = 0, const double price = 0.0): first
Stock::Stock(const std::string &company, const long num = 0, const double price = 0.0): second
Stock::Stock(const std::string &company, const long num = 0, const double price = 0.0): third
Stock::Stock(const std::string &company, const long num = 0, const double price = 0.0): fourth

Stock holdings:
Company: first
  Shares = 12  Share Price = $20.000  Total Worth = $240.00
Company: second
  Shares = 200  Share Price = $2.000  Total Worth = $400.00
Company: third
  Shares = 130  Share Price = $3.250  Total Worth = $422.50
Company: fourth
  Shares = 60  Share Price = $6.500  Total Worth = $390.00

Most valuable holding:
Company: third
  Shares = 130  Share Price = $3.250  Total Worth = $422.50
Stock::~Stock(): fourth
Stock::~Stock(): third
Stock::~Stock(): second
Stock::~Stock(): first
请按任意键继续. . .

Incidentally, knowing about the this pointer makes it easier to see how C++ works under the skin. For example, the original Unix implementation used a C++ front-end cfront that converted C++ programs to C programs.
知道 this 指针就可以更深入了解 C++ 的工作方式。例如,最初的 UNIX 实现使用 C++ 前端 cfront 将 C++ 程序转换为 C 程序。

C++ method definition:

void Stock::Show() const {
	// set format to #.###
	std::ios_base::fmtflags original = std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::streamsize precision = std::cout.precision(3);

	std::cout << "Company: " << company_ << "\n  Shares = " << shares_;
	std::cout << "  Share Price = $" << share_val_;

	// set format to #.##
	std::cout.precision(2);
	std::cout << "  Total Worth = $" << total_val_ << '\n';

	// restore original format
	std::cout.setf(original, std::ios_base::floatfield);
	std::cout.precision(precision);
}

C-style definition:

void Show(const Stock * this) {
	// set format to #.###
	std::ios_base::fmtflags original = std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::streamsize precision = std::cout.precision(3);

	std::cout << "Company: " << this->company_ << "\n  Shares = " << this->shares_;
	std::cout << "  Share Price = $" << this->share_val_;

	// set format to #.##
	std::cout.precision(2);
	std::cout << "  Total Worth = $" << this->total_val_ << '\n';

	// restore original format
	std::cout.setf(original, std::ios_base::floatfield);
	std::cout.precision(precision);
}

That is, it converted a Stock:: qualifier to a function argument that is a pointer to Stock and then uses the pointer to access class members.
Stock:: 限定符转换为函数参数 (指向 Stock 的指针),然后用这个指针来访问类成员。

Similarly, the front end converted function calls like

top.Show();

to this:

Show(&top);

In this fashion, the this pointer is assigned the address of the invoking object. The actual details might be more involved.
将调用对象的地址赋给了 this 指针,实际情况可能更复杂些。

References

[1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/
[2] C++ Primer Plus, 6th Edition, https://www.informit.com/store/c-plus-plus-primer-plus-9780321776402

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

详细解释Redis的SET NX命令

详细解释Redis的SET NX命令 SET NX 命令是 Redis 中用于实现分布式锁的一个重要命令。它的语法和用法如下&#xff1a; SET key value NX [EX seconds | PX milliseconds]参数解释 key&#xff1a;要设置的键名。value&#xff1a;要设置的键值&#xff0c;通常用一个唯一标…

什么是无头浏览器?

简而言之&#xff0c;无头浏览器是没有图形用户界面 &#xff08;GUI&#xff09; 的 Web 浏览器。GUI 包括用户与之交互的数字元素&#xff0c;例如按钮、图标和窗口。但是&#xff0c;关于无头浏览器&#xff0c;您需要了解的还有很多。 在本文中&#xff0c;您将了解什么是…

2007-2022年 省级-绿色农业合作社数量相关数据整理

绿色农业合作社作为一种推动农业可持续发展的组织形式&#xff0c;对于促进环境保护、提高农产品质量和增加农民收入等方面具有重要作用。以下是对省级绿色农业合作社数量相关数据的介绍&#xff1a; 数据简介 定义&#xff1a;绿色农业合作社是由农民、农业专家、企业家等组…

关于Redisson分布式锁的用法

关于Redisson分布式锁的用法 Redisson是一个基于Redis的Java分布式对象和服务框架&#xff0c;它提供了多种分布式锁的实现&#xff0c;包括可重入锁、公平锁、读写锁等。Redisson实现分布式锁的核心原理主要依赖于Redis的数据结构和Redisson框架提供的高级功能。以下详细讲解…

基于RK3588的GMSL、FPDLink 、VByone及MIPI等多种摄像模组,适用于车载、机器人工业图像识别领域

机器人&工业摄像头 针对机器人视觉与工业检测视觉&#xff0c;信迈自主研发和生产GMSL、FPDLink 、VByone及MIPI等多种摄像模组&#xff0c;并为不同应用场景提供多种视场角度和镜头。拥有资深的图像算法和图像ISP专家团队&#xff0c;能够在软件驱动层开发、ISP算法、FPG…

sql-语句

文章目录 SQL语句的学习sql是什么sql的内置命令sql的种类sql mode库&#xff0c;表属性介绍&#xff1a;字符集&#xff0c;存储引擎列的数据类型&#xff1a;数字&#xff0c;字符串&#xff0c;时间列的约束DDL: 数据定义语言库表 Online DDL(ALGORITHM) *DML :数据操纵语言资…

算法:链表

目录 链表的技巧和操作总结 常用技巧&#xff1a; 链表中的常用操作 题目一&#xff1a;反转一个单链表 题目二&#xff1a;链表的中间结点 题目三&#xff1a;返回倒数第k个结点 题目四&#xff1a;合并两个有序链表 题目五&#xff1a;移除链表元素 题目六&#xff…

033基于SSM+Jsp的多用户博客个人网站

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

GPIO和PIN

文章目录 1 GPIO和Pin1.1 GPIO和Pin基础概念1.2 GPIO输入模式1.3 GPIO输出模式1.4 GPIO的HAL库1.4.1 一些HAL库表示1.4.2 HAL库常用GPIO函数1.4.3 GPIO点亮led灯程序例子 1 GPIO和Pin 1.1 GPIO和Pin基础概念 ​ 单片机有很多的引脚&#xff0c;为了操控每一个引脚&#xff0c…

JVM原理(四):JVM垃圾收集算法与分代收集理论

从如何判定消亡的角度出发&#xff0c;垃圾收集算法可以划分为“引用计数式垃圾收集”和“追踪式垃圾收集”两大类。 本文主要介绍的是追踪式垃圾收集。 1. 分代收集理论 当代垃圾收集器大多遵循“分代收集”的理论进行设计&#xff0c;它建立在两个假说之上&#xff1a; 弱分…

Git企业开发---初识Git

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 引言 不知道大家有没有经历这种困惑&#xff0c;当我们要去交某文档时&#xff0c;总是要进行修改&#xff0c;修改后再交…

【知识学习】Unity3D中Shader Graph的概念及使用方法示例

Unity3D中的Shader Graph是一个强大的可视化Shader编辑工具&#xff0c;它允许用户通过拖拽和连接节点的方式来创建Shader&#xff0c;而不是通过传统的编写代码的方式。Shader Graph使得Shader的创建过程更加直观和易于理解&#xff0c;特别是对于那些不熟悉Shader语言编程的美…

19.《C语言》——【如何理解static和extern?】

&#x1f387;开场语 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…

MDA管理层讨论与分析内容信息披露情感分析数据(2010-2022年)

数据简介&#xff1a;MD&A通常是指管理层讨论与分析&#xff08;Management Discussion & Analysis&#xff09;&#xff0c;是上市公司年报中一个重要的部分&#xff0c;主要包含公司经营业绩的讨论&#xff0c;以及未来前景的预测等。MD&A可以帮助投资者更好地理…

leetcode 第133场双周赛 100333.统计逆序对的数目【计数dp/滚动数组/前缀和优化】

分析&#xff1a; 先考虑如下问题。 求长度为n&#xff0c;逆序对为m的排列数量。 可以考虑dp&#xff0c;dp[i][j]定义为长度为i&#xff0c;逆序对为j的排列数量。 dp[1][0] 1; //枚举排列长度&#xff0c;或者认为枚举当前需要插到长度为i-1的排列中的数字 for(int i 1…

笔记本电脑安装CentOS

正文共&#xff1a;1234 字 24 图&#xff0c;预估阅读时间&#xff1a;2 分钟 前面我们对VPP进行了多次介绍&#xff08;羡慕&#xff01;大佬的VPP能达到180G性能&#xff0c;而我的却只有13.5G&#xff09;&#xff0c;可以发现他的很多优点&#xff0c;但是我们也可以发现它…

socket编程常见操作

1、连接的建立 分为两种&#xff1a;服务端处理接收客户端的连接&#xff1b;服务端作为客户端连接第三方服务 //作为服务端 int listenfd socket(AF_INET, SOCK_STREAM, 0); bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) listen(listenfd, 10); //…

【单片机毕业设计11-基于stm32c8t6的智能水质检测】

【单片机毕业设计11-基于stm32c8t6的智能水质检测】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇11基于stm32的智能水质检测系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 -------------…

武汉星起航:亚马逊欧洲站潮流指南,满足年轻人选品需求

在充满活力的20-30岁年龄段&#xff0c;年轻人们充满朝气&#xff0c;追求时尚与品质&#xff0c;对生活充满无限期待。亚马逊欧洲站作为全球领先的电商平台&#xff0c;为这一年龄段的人群提供了丰富多样的商品选择。武汉星起航将为您介绍亚马逊欧洲站针对20-30岁人群的选品攻…

三元表达式解析器

题意&#xff1a;其实本质上就是三目运算 &#xff0c;只不过跟我们以往的三目运算不同的是&#xff0c;这一系列的运算可以把T 和 F 都参与到运算中。设x5 表达式 x>2?T:F 最终返回T. 思路&#xff1a; 1.从后往前遍历字符数组 2.如果遇到的是 非&#xff1f;和 非&…