1. this 指针

C++ 中,每一个对象都能通过 this 指针来访问自己的地址。 this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。

友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

在类中,关键字 this 包含当前对象的地址,换句话说,其值为 &object 。当您在类成员方法中调用其他成员方法时,编译器将隐式地传递 this 指针—函数调用中不可见的参数:

class Human
{private:void Talk(string msg){cout << msg << endl;}public:void IntroduceSelf(){Talk("hello world"); // Talk(this, "hello world")}
}

方法 IntroduceSelf() 使用私有成员 Talk() 在屏幕上显示一句话。实际上,编译器将在调用 Talk 时嵌入 this 指针,即 Talk(this, "hello world")

从编程的角度看, this 的用途不多,且大多数情况下都是可选的。见下:

void SetAge(int humansAge)
{this->age = humansAge; // same as age = humansAge
}

调用静态方法时,不会隐式地传递 this 指针,因为静态函数不与类实例相关联,而由所有实例共享。要在静态函数中使用实例变量,应显式地声明一个形参,并将实参设置为 this 指针。

因为 this 的目的总是指向“这个”对象,所以 this 是一个常量指针,我们不允许改变 this 中保存的地址。

2. 指向类的指针

一个指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 -> ,就像访问指向结构的指针一样。与所有的指针一样,您必须在使用指针之前,对指针进行初始化。

#include <iostream>
#include <string>
using namespace std;class Box
{public:// 构造函数声明Box(double, double, double);double Volume();private:double length;     // Length of a boxdouble breadth;    // Breadth of a boxdouble height;     // Height of a box
};Box::Box(double l=2.0, double b=2.0, double h=2.0)
{ cout <<"Constructor called." << endl;length = l;breadth = b;height = h;
}double Box::Volume()
{return length * breadth * height;
}int main(void)
{Box Box1(3.3, 1.2, 1.5);    // Declare box1Box Box2(8.5, 6.0, 2.0);    // Declare box2Box *ptrBox;                // Declare pointer to a class.// 保存第一个对象的地址ptrBox = &Box1;// 现在尝试使用成员访问运算符来访问成员cout << "Volume of Box1: " << ptrBox->Volume() << endl;// 保存第二个对象的地址ptrBox = &Box2;// 现在尝试使用成员访问运算符来访问成员cout << "Volume of Box2: " << ptrBox->Volume() << endl;return 0;
}

3. 类静态成员

可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。

我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化,如下面的实例所示。

3.1 静态成员变量

静态成员数据也可以分为共有的(Public)和私有的(Private),静态成员数据的声明方法为:

static data_type data_name;

由于静态成员数据不是仅仅属于某一个具体对象的,所以它不能再构造函数中被初始化。否则岂不是每创建一个对象,静态成员数据都要被初始化一次?

如果类的头文件会被直接或间接地重复包含,则静态成员数据也会被重复初始化。为了避免这个问题,我们可以将类的声明和定义分离。

如果类的头文件绝对不会被重复包含,那么把静态成员数据的初始化放在类的头文件中也是勉强可以接受的。

静态成员数据的初始化语句为:

数据类型 类名::静态成员数据=初始值;

静态成员数据是某一个类所具有的属性,而不是某一个对象的属性,所以它的存在并不依赖于对象。
示例代码:

#include <iostream>
#include <string>
using namespace std;class Box
{public:Box(double, double, double);  // 构造函数声明double Volume();static int objectCount;private:double length;     // Length of a boxdouble breadth;    // Breadth of a boxdouble height;     // Height of a box
};// 初始化类 Box 的静态成员
int Box::objectCount = 0;Box::Box(double l=2.0, double b=2.0, double h=2.0)
{ cout <<"Constructor called." << endl;length = l;breadth = b;height = h;objectCount++; // 每次创建对象时增加 1
}double Box::Volume()
{return length * breadth * height;
}int main(void)
{Box Box1(3.3, 1.2, 1.5);    // 声明 box1Box Box2(8.5, 6.0, 2.0);    // 声明 box2// 输出对象的总数// Total objects: 2cout << "Total objects: " << Box::objectCount << endl;return 0;
}

3.2 静态成员函数

既然成员数据可以属于某一个类而不属于某一个具体的对象,那么成员函数也可以这样。在 C++ 中静态成员函数也是属于某一个类而不属于某一个具体的对象的。

静态成员函数的声明方法为:

static 返回值类型 函数名(参数表);

不过在定义静态成员函数时,却不能出现 static

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。

由于静态成员函数是属于类的,不是属于某一个具体的对象,所以它分不清楚到底是哪个对象的非静态成员数据,故而不能访问非静态成员数据。

所以静态成员函数只能访问静态成员变量数据、其他静态成员函数和类外部的其他函数。

静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。

静态成员函数与普通成员函数的区别:

  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。
#include <iostream>
#include <string>
using namespace std;class Box
{public:Box(double, double, double);  // 构造函数声明double Volume();static int objectCount;static int getCount();private:double length;     // Length of a boxdouble breadth;    // Breadth of a boxdouble height;     // Height of a box
};// 初始化类 Box 的静态成员
int Box::objectCount = 0;// 在定义静态成员函数时,却不能出现 `static`
int Box::getCount()
{return objectCount;
}
Box::Box(double l=2.0, double b=2.0, double h=2.0)
{ cout <<"Constructor called." << endl;length = l;breadth = b;height = h;objectCount++; // 每次创建对象时增加 1
}double Box::Volume()
{return length * breadth * height;
}int main(void)
{// 在创建对象之前输出对象的总数cout << "Inital Stage Count: " << Box::getCount() << endl;Box Box1(3.3, 1.2, 1.5);    // 声明 box1Box Box2(8.5, 6.0, 2.0);    // 声明 box2// 在创建对象之后输出对象的总数cout << "Final Stage Count: " << Box2.getCount() << endl;return 0;
}

其中 Box2.getCount() 等价于 Box::getCount()。即 类型::静态成员函数(参数列表) 等价于 对象名.静态成员函数(参数列表),但更推荐前者,比较符合静态成员函数定义。

输出结果:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2

类中特殊成员变量的初始化问题:

  • 常量变量:必须通过构造函数参数列表进行初始化。
  • 引用变量:必须通过构造函数参数列表进行初始化。
  • 普通静态变量:要在类外通过"::"初始化。
  • 静态整型常量:可以直接在定义的时候初始化。
  • 静态非整型常量:不能直接在定义的时候初始化。要在类外通过"::"初始化。

C++ 笔记(18)— 类和对象(this 指针、指向类的指针、类静态成员变量和函数)相关推荐

  1. 类是对象的抽象,对象是类的实例

    类是对象的抽象,对象是类的实例 是 正确的 看:https://www.cnblogs.com/marlanchen/p/11563929.html[转载]

  2. 类和对象(一)this指针详解

    索引 类的定义 访问限定符 类的封装 类的作用域 类的实例化 类大小计算 This指针 1,This 指针的引入 2,This的特点 面试题: 类的定义 在C语言中,结构体只能定义变量,但是在C++中 ...

  3. Kotlin学习笔记 第二章 类与对象 第十节 内部类嵌套类

    参考链接 Kotlin官方文档 https://kotlinlang.org/docs/home.html 中文网站 https://www.kotlincn.net/docs/reference/p ...

  4. 类和对象编程(九):类的静态成员

    C++ 类的静态成员 我们可以使用 static 关键字来把类成员定义为静态的.当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本. 静态成员在类的所有对象中是共享的. ...

  5. Java 类和对象——抽象类、接口、Object类

    本文章继续来介绍类和对象的知识.重点介绍抽象类和接口,Object类只做简单介绍. 现在,定义一个Shape类(形状类),当不同的对象去调用的时候,就会画出不同的图形,使用圆这个对象去调用,就会画出⚪ ...

  6. python 类和对象 有必要学吗_类与对象-python学习19

    类与对象 类:我们常用类来划分一个个特定的群体:我们所说的类,是物以类聚的类,是分门别类的类,是多个类似事物组成的群体的统称.类的概念能帮助我们快速理解和判断事物的性质. 类(class),比如整数. ...

  7. java类与对象实验报告心得体会_Java类与对象实验报告.doc

    西 安 邮 电 大 学 (计算机学院) 课内实验报告 实验名称: 类与对象 专业名称: 计算机科学与技术 班 级: 计科1405班 学生姓名: 高宏伟 学 号: 指导教师: 刘霞林 实验日期: 201 ...

  8. c#类属性和实例属性_Visual C#类和对象的创建方式,定义类,实例化对象,实例讲解...

    定义类 类由class member类成员组成,包含字段.属性.方法和事件.其中字段和属性为类的数据成员,用来存储数据:方法负责数据的传递和运算.使用类之前,要进行声明,声明的语法如下: Class ...

  9. 类和对象编程(一):类成员函数

    C++ 类成员函数 类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样.类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员. 让我们看看之前定义的 ...

最新文章

  1. SpringBoot2.x 官方推荐缓存框架-Caffeine高性能设计剖析
  2. UC Berkeley CS188 Intro to AI
  3. pdf怎么压缩大小?
  4. 6 redhat 查看rtc时间_Linux EasyStack-Redhat安装Docker
  5. 失败如何助你升入最高管理层
  6. 电视开机还要看广告?超80%的人一秒都忍不了
  7. CXF之jaxws:endpoint对spring bean的引用
  8. springcloud 微服务鉴权_推荐 1w+ 星标的 SpringCloud 微服务项目,开发脚手架
  9. ImportError: libgfortran.so.4: cannot open shared object file: No such file or directory
  10. 小白可以来看看磁盘与文件管理实验
  11. matlab 产生任意概率密度的联合分布
  12. 微信小程序 内容评论-回复评论-回复回复的实现
  13. 各种语言如何连接到 OceanBase
  14. linux网卡驱动内核文件目录,LINUX内核升级更新网卡驱动
  15. win10打开蓝牙_用了N年也未必知!Win10竟藏有这么多实用功能
  16. 《深入理解JAVA虚拟机》周志明 第三版 - 第一章 走近JAVA
  17. android rmvb格式下载,顶峰-Android手机视频转换器
  18. 使用css和js实现刮刮乐(简单易懂还有趣)
  19. 输出以个小于1万亿的正整数的拼音读法
  20. 「杂谈」苏州要想成为一线城市,还需要放几个大招

热门文章

  1. Map的分类和不同的应用场景
  2. Centos7.4安装Nginx
  3. SpringCloud Alibaba微服务实战(一) - 基础环境搭建
  4. 残差复合正态分布的重要性
  5. Bert系列(三)——源码解读之Pre-train
  6. PyTorch学习笔记——softmax和log_softmax的区别、CrossEntropyLoss() 与 NLLLoss() 的区别、log似然代价函数...
  7. TVM交叉编译和远程RPC
  8. NVIDIA FFmpeg 转码技术分析
  9. CodeGen融合核心扩展定制文件
  10. 基于TensorRT的BERT实时自然语言理解(下)