780 lines
17 KiB
Markdown
780 lines
17 KiB
Markdown
|
---
|
|||
|
id: 面对对象
|
|||
|
title: 面对对象
|
|||
|
sidebar_position: 5
|
|||
|
data: 2022年5月26日
|
|||
|
---
|
|||
|
|
|||
|
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。
|
|||
|
|
|||
|
类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。
|
|||
|
|
|||
|
## 类
|
|||
|
|
|||
|
类定义是以关键字 **class** 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。
|
|||
|
|
|||
|
### 定义
|
|||
|
|
|||
|
```cpp
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
double length; // 盒子的长度
|
|||
|
double breadth; // 盒子的宽度
|
|||
|
double height; // 盒子的高度
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
### 创建
|
|||
|
|
|||
|
对象 Box1 和 Box2 拥有独立的数据成员。
|
|||
|
|
|||
|
```cpp
|
|||
|
Box Box1; // 声明 Box1,类型为 Box
|
|||
|
Box Box2; // 声明 Box2,类型为 Box
|
|||
|
```
|
|||
|
|
|||
|
### 实例
|
|||
|
|
|||
|
类的对象的公共数据成员可以使用直接成员访问运算符 (.) 来访问。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
};
|
|||
|
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Box Box1; // 声明 Box1,类型为 Box
|
|||
|
Box Box2; // 声明 Box2,类型为 Box
|
|||
|
double volume = 0.0; // 用于存储体积
|
|||
|
|
|||
|
// box 1 详述
|
|||
|
Box1.height = 5.0;
|
|||
|
Box1.length = 6.0;
|
|||
|
Box1.breadth = 7.0;
|
|||
|
|
|||
|
// box 2 详述
|
|||
|
Box2.height = 10.0;
|
|||
|
Box2.length = 12.0;
|
|||
|
Box2.breadth = 13.0;
|
|||
|
|
|||
|
// box 1 的体积
|
|||
|
volume = Box1.height * Box1.length * Box1.breadth;
|
|||
|
cout << "Box1 的体积:" << volume <<endl;
|
|||
|
|
|||
|
// box 2 的体积
|
|||
|
volume = Box2.height * Box2.length * Box2.breadth;
|
|||
|
cout << "Box2 的体积:" << volume <<endl;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Box1 的体积:210
|
|||
|
Box2 的体积:1560
|
|||
|
```
|
|||
|
|
|||
|
## 类的详解
|
|||
|
|
|||
|
### 构造函数
|
|||
|
|
|||
|
类的构造函数是类的一种特殊的成员函数,它会在**每次创建类的新对象时执行。**
|
|||
|
|
|||
|
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
|
|||
|
|
|||
|
如果需要,构造函数也可以带有参数,可以通过重载实现构造函数多元化。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Line
|
|||
|
{
|
|||
|
public:
|
|||
|
void setLength( double len );
|
|||
|
double getLength( void );
|
|||
|
Line(); // 这是构造函数
|
|||
|
|
|||
|
private:
|
|||
|
double length;
|
|||
|
};
|
|||
|
|
|||
|
// 成员函数定义,包括构造函数
|
|||
|
Line::Line(void)
|
|||
|
{
|
|||
|
cout << "Object is being created" << endl;
|
|||
|
}
|
|||
|
|
|||
|
void Line::setLength( double len )
|
|||
|
{
|
|||
|
length = len;
|
|||
|
}
|
|||
|
|
|||
|
double Line::getLength( void )
|
|||
|
{
|
|||
|
return length;
|
|||
|
}
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Line line;
|
|||
|
|
|||
|
// 设置长度
|
|||
|
line.setLength(6.0);
|
|||
|
cout << "Length of line : " << line.getLength() <<endl;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### 初始化列表
|
|||
|
|
|||
|
假设有一个类 C,具有多个字段 X、Y、Z 等需要进行初始化,同理地,您可以使用上面的语法,只需要在不同的字段使用逗号进行分隔,如下所示:
|
|||
|
|
|||
|
```cpp
|
|||
|
C::C( double a, double b, double c): X(a), Y(b), Z(c)
|
|||
|
{
|
|||
|
....
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**等同于:**
|
|||
|
|
|||
|
```
|
|||
|
C::C( double a, double b, double c)
|
|||
|
{
|
|||
|
X = a;
|
|||
|
Y = b;
|
|||
|
Z = c;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### 拷贝构造函数
|
|||
|
|
|||
|
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
|
|||
|
|
|||
|
- 通过使用另一个同类型的对象来初始化新创建的对象。
|
|||
|
- 复制对象把它作为参数传递给函数。
|
|||
|
- 复制对象,并从函数返回这个对象。
|
|||
|
|
|||
|
如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:
|
|||
|
|
|||
|
```cpp
|
|||
|
classname (const classname &obj) {
|
|||
|
// 构造函数的主体
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Line
|
|||
|
{
|
|||
|
public:
|
|||
|
int getLength( void );
|
|||
|
Line( int len ); // 简单的构造函数
|
|||
|
Line( const Line &obj); // 拷贝构造函数
|
|||
|
~Line(); // 析构函数
|
|||
|
|
|||
|
private:
|
|||
|
int *ptr;
|
|||
|
};
|
|||
|
|
|||
|
// 成员函数定义,包括构造函数
|
|||
|
Line::Line(int len)
|
|||
|
{
|
|||
|
cout << "调用构造函数" << endl;
|
|||
|
// 为指针分配内存
|
|||
|
ptr = new int;
|
|||
|
*ptr = len;
|
|||
|
}
|
|||
|
|
|||
|
Line::Line(const Line &obj)
|
|||
|
{
|
|||
|
cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
|
|||
|
ptr = new int;
|
|||
|
*ptr = *obj.ptr; // 拷贝值
|
|||
|
}
|
|||
|
|
|||
|
Line::~Line(void)
|
|||
|
{
|
|||
|
cout << "释放内存" << endl;
|
|||
|
delete ptr;
|
|||
|
}
|
|||
|
int Line::getLength( void )
|
|||
|
{
|
|||
|
return *ptr;
|
|||
|
}
|
|||
|
|
|||
|
void display(Line obj)
|
|||
|
{
|
|||
|
cout << "line 大小 : " << obj.getLength() <<endl;
|
|||
|
}
|
|||
|
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Line line(10);
|
|||
|
|
|||
|
display(line);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
调用构造函数
|
|||
|
调用拷贝构造函数并为指针 ptr 分配内存
|
|||
|
line 大小 : 10
|
|||
|
释放内存
|
|||
|
释放内存
|
|||
|
```
|
|||
|
|
|||
|
### 析构函数
|
|||
|
|
|||
|
类的**析构函数**是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
|
|||
|
|
|||
|
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
|
|||
|
|
|||
|
#### 实例
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Line
|
|||
|
{
|
|||
|
public:
|
|||
|
void setLength( double len );
|
|||
|
double getLength( void );
|
|||
|
Line(); // 这是构造函数声明
|
|||
|
~Line(); // 这是析构函数声明
|
|||
|
|
|||
|
private:
|
|||
|
double length;
|
|||
|
};
|
|||
|
|
|||
|
// 成员函数定义,包括构造函数
|
|||
|
Line::Line(void)
|
|||
|
{
|
|||
|
cout << "Object is being created" << endl;
|
|||
|
}
|
|||
|
Line::~Line(void)
|
|||
|
{
|
|||
|
cout << "Object is being deleted" << endl;
|
|||
|
}
|
|||
|
|
|||
|
void Line::setLength( double len )
|
|||
|
{
|
|||
|
length = len;
|
|||
|
}
|
|||
|
|
|||
|
double Line::getLength( void )
|
|||
|
{
|
|||
|
return length;
|
|||
|
}
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Line line;
|
|||
|
|
|||
|
// 设置长度
|
|||
|
line.setLength(6.0);
|
|||
|
cout << "Length of line : " << line.getLength() <<endl;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Object is being created
|
|||
|
Length of line : 6
|
|||
|
Object is being deleted
|
|||
|
```
|
|||
|
|
|||
|
### 访问修饰符
|
|||
|
|
|||
|
数据封装是面向对象编程的一个重要特点,它防止函数直接访问类类型的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记 **public、private、protected** 来指定的。关键字 **public、private、protected** 称为访问修饰符。
|
|||
|
|
|||
|
```cpp
|
|||
|
class Base {
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
// 公有成员
|
|||
|
|
|||
|
protected:
|
|||
|
|
|||
|
// 受保护成员
|
|||
|
|
|||
|
private:
|
|||
|
|
|||
|
// 私有成员
|
|||
|
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
- **公有(public)成员**:公有成员在程序中类的外部是**可访问的**。
|
|||
|
- **私有(private)成员**:私有成员变量或函数在类的外部是**不可访问、查看的**。只有类和友元函数可以访问私有成员。**默认情况下,类的所有成员都是私有的。**
|
|||
|
- **保护(protected)成员**:保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
|
|||
|
|
|||
|
#### 继承中的特点
|
|||
|
|
|||
|
有 public, protected, private 三种继承方式,它们相应地改变了基类成员的访问属性。
|
|||
|
|
|||
|
**public 继承:**
|
|||
|
|
|||
|
| 基类 | public | protected | private |
|
|||
|
| ------ | ------ | --------- | ------- |
|
|||
|
| 派生类 | 可 | 可 | 不可 |
|
|||
|
| 类外 | 可 | 不可 | 不可 |
|
|||
|
|
|||
|
**protected 继承:**
|
|||
|
|
|||
|
| 基类 | public | protected | private |
|
|||
|
| ------ | ------ | --------- | ------- |
|
|||
|
| 派生类 | 可 | 可 | 不可 |
|
|||
|
| 类外 | 不可 | 不可 | 不可 |
|
|||
|
|
|||
|
**private 继承:**
|
|||
|
|
|||
|
| 基类 | public | protected | private |
|
|||
|
| ------ | ------ | --------- | ------- |
|
|||
|
| 派生类 | 可 | 可 | 不可 |
|
|||
|
| 类外 | 不可 | 不可 | 不可 |
|
|||
|
|
|||
|
无论哪种继承方式,有两点都没有改变:
|
|||
|
|
|||
|
- private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
|
|||
|
- protected 成员可以被派生类访问。
|
|||
|
|
|||
|
### 成员函数
|
|||
|
|
|||
|
类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员。
|
|||
|
|
|||
|
```cpp
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
|
|||
|
double getVolume(void)
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
在类的内部声明函数后,可以在类的外部使用**范围解析运算符 ::** 定义该函数,在 **::** 运算符之前必须使用类名。
|
|||
|
|
|||
|
```cpp
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
|
|||
|
double getVolume(void);// 必须在类的内部声明函数
|
|||
|
};
|
|||
|
|
|||
|
double Box::getVolume(void)
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
|
|||
|
double getVolume(void)
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
|
|||
|
// 成员函数声明
|
|||
|
void setLength( double len );
|
|||
|
void setBreadth( double bre );
|
|||
|
void setHeight( double hei );
|
|||
|
};
|
|||
|
|
|||
|
// 成员函数定义
|
|||
|
void Box::setLength( double len )
|
|||
|
{
|
|||
|
length = len;
|
|||
|
}
|
|||
|
|
|||
|
void Box::setBreadth( double bre )
|
|||
|
{
|
|||
|
breadth = bre;
|
|||
|
}
|
|||
|
|
|||
|
void Box::setHeight( double hei )
|
|||
|
{
|
|||
|
height = hei;
|
|||
|
}
|
|||
|
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Box Box1; // 声明 Box1,类型为 Box
|
|||
|
Box Box2; // 声明 Box2,类型为 Box
|
|||
|
double volume = 0.0; // 用于存储体积
|
|||
|
|
|||
|
// box 1 详述
|
|||
|
Box1.setLength(6.0);
|
|||
|
Box1.setBreadth(7.0);
|
|||
|
Box1.setHeight(5.0);
|
|||
|
|
|||
|
// box 2 详述
|
|||
|
Box2.setLength(12.0);
|
|||
|
Box2.setBreadth(13.0);
|
|||
|
Box2.setHeight(10.0);
|
|||
|
|
|||
|
// box 1 的体积
|
|||
|
volume = Box1.getVolume();
|
|||
|
cout << "Box1 的体积:" << volume <<endl;
|
|||
|
|
|||
|
// box 2 的体积
|
|||
|
volume = Box2.getVolume();
|
|||
|
cout << "Box2 的体积:" << volume <<endl;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```cpp
|
|||
|
Box1 的体积: 210
|
|||
|
Box2 的体积: 1560
|
|||
|
```
|
|||
|
|
|||
|
### 友元函数
|
|||
|
|
|||
|
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是**友元函数并不是成员函数。**
|
|||
|
|
|||
|
**友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类**,在这种情况下,整个类及其所有成员都是友元。
|
|||
|
|
|||
|
```cpp
|
|||
|
class Box
|
|||
|
{
|
|||
|
double width;
|
|||
|
public:
|
|||
|
double length;
|
|||
|
friend void printWidth( Box box ); // 友元函数
|
|||
|
friend class ClassTwo; // 友元类
|
|||
|
void setWidth( double wid );
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
double width;
|
|||
|
public:
|
|||
|
friend void printWidth( Box box );
|
|||
|
void setWidth( double wid );
|
|||
|
};
|
|||
|
|
|||
|
// 成员函数定义
|
|||
|
void Box::setWidth( double wid )
|
|||
|
{
|
|||
|
width = wid;
|
|||
|
}
|
|||
|
|
|||
|
// 请注意:printWidth() 不是任何类的成员函数
|
|||
|
void printWidth( Box box )
|
|||
|
{
|
|||
|
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
|
|||
|
cout << "Width of box : " << box.width <<endl;
|
|||
|
}
|
|||
|
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
Box box;
|
|||
|
|
|||
|
// 使用成员函数设置宽度
|
|||
|
box.setWidth(10.0);
|
|||
|
|
|||
|
// 使用友元函数输出宽度
|
|||
|
printWidth( box );
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Width of box : 10
|
|||
|
```
|
|||
|
|
|||
|
### 内联函数
|
|||
|
|
|||
|
C++ **内联函数**是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
|
|||
|
|
|||
|
内联的主要不同是:它会复制源函数代码到调用的位置,而不像普通函数一样进行现场保护、跳转执行然后恢复现场等操作,可以使程序效率提高,比较典型的空间换取时间的思路。
|
|||
|
|
|||
|
如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 **inline**,在调用函数之前需要对函数进行定义。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
inline int Max(int x, int y)
|
|||
|
{
|
|||
|
return (x > y)? x : y;
|
|||
|
}
|
|||
|
|
|||
|
// 程序的主函数
|
|||
|
int main( )
|
|||
|
{
|
|||
|
|
|||
|
cout << "Max (20,10): " << Max(20,10) << endl;
|
|||
|
cout << "Max (0,200): " << Max(0,200) << endl;
|
|||
|
cout << "Max (100,1010): " << Max(100,1010) << endl;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```cpp
|
|||
|
Max (20,10): 20
|
|||
|
Max (0,200): 200
|
|||
|
Max (100,1010): 1010
|
|||
|
```
|
|||
|
|
|||
|
### 静态成员
|
|||
|
|
|||
|
可以使用 **static** 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
|
|||
|
|
|||
|
静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 **::** 来重新声明静态变量从而对它进行初始化,如下面的实例所示。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
static int objectCount;
|
|||
|
// 构造函数定义
|
|||
|
Box(double l=2.0, double b=2.0, double h=2.0)
|
|||
|
{
|
|||
|
cout <<"Constructor called." << endl;
|
|||
|
length = l;
|
|||
|
breadth = b;
|
|||
|
height = h;
|
|||
|
// 每次创建对象时增加 1
|
|||
|
objectCount++;
|
|||
|
}
|
|||
|
double Volume()
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
private:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
};
|
|||
|
|
|||
|
// 初始化类 Box 的静态成员
|
|||
|
int Box::objectCount = 0;
|
|||
|
|
|||
|
int main(void)
|
|||
|
{
|
|||
|
Box Box1(3.3, 1.2, 1.5); // 声明 box1
|
|||
|
Box Box2(8.5, 6.0, 2.0); // 声明 box2
|
|||
|
|
|||
|
// 输出对象的总数
|
|||
|
cout << "Total objects: " << Box::objectCount << endl;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Constructor called.
|
|||
|
Constructor called.
|
|||
|
Total objects: 2
|
|||
|
```
|
|||
|
|
|||
|
### 静态成员函数
|
|||
|
|
|||
|
如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,**静态函数**只要使用类名加范围解析运算符 **::** 就可以访问。
|
|||
|
|
|||
|
静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
|
|||
|
|
|||
|
静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。
|
|||
|
|
|||
|
**静态成员函数与普通成员函数的区别:**
|
|||
|
|
|||
|
- 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
|
|||
|
|
|||
|
- 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
static int objectCount;
|
|||
|
// 构造函数定义
|
|||
|
Box(double l=2.0, double b=2.0, double h=2.0)
|
|||
|
{
|
|||
|
cout <<"Constructor called." << endl;
|
|||
|
length = l;
|
|||
|
breadth = b;
|
|||
|
height = h;
|
|||
|
// 每次创建对象时增加 1
|
|||
|
objectCount++;
|
|||
|
}
|
|||
|
double Volume()
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
static int getCount()
|
|||
|
{
|
|||
|
return objectCount;
|
|||
|
}
|
|||
|
private:
|
|||
|
double length; // 长度
|
|||
|
double breadth; // 宽度
|
|||
|
double height; // 高度
|
|||
|
};
|
|||
|
|
|||
|
// 初始化类 Box 的静态成员
|
|||
|
int Box::objectCount = 0;
|
|||
|
|
|||
|
int main(void)
|
|||
|
{
|
|||
|
|
|||
|
// 在创建对象之前输出对象的总数
|
|||
|
cout << "Inital Stage Count: " << Box::getCount() << endl;
|
|||
|
|
|||
|
Box Box1(3.3, 1.2, 1.5); // 声明 box1
|
|||
|
Box Box2(8.5, 6.0, 2.0); // 声明 box2
|
|||
|
|
|||
|
// 在创建对象之后输出对象的总数
|
|||
|
cout << "Final Stage Count: " << Box::getCount() << endl;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Inital Stage Count: 0
|
|||
|
Constructor called.
|
|||
|
Constructor called.
|
|||
|
Final Stage Count: 2
|
|||
|
```
|
|||
|
|
|||
|
### this 指针
|
|||
|
|
|||
|
在 C++ 中,每一个对象都能通过 **this** 指针来访问自己的地址。**this** 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
|
|||
|
|
|||
|
友元函数没有 **this** 指针,因为友元不是类的成员。只有成员函数才有 **this** 指针。
|
|||
|
|
|||
|
```cpp
|
|||
|
#include <iostream>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
class Box
|
|||
|
{
|
|||
|
public:
|
|||
|
// 构造函数定义
|
|||
|
Box(double l=2.0, double b=2.0, double h=2.0)
|
|||
|
{
|
|||
|
cout <<"Constructor called." << endl;
|
|||
|
length = l;
|
|||
|
breadth = b;
|
|||
|
height = h;
|
|||
|
}
|
|||
|
double Volume()
|
|||
|
{
|
|||
|
return length * breadth * height;
|
|||
|
}
|
|||
|
int compare(Box box)
|
|||
|
{
|
|||
|
return this->Volume() > box.Volume();
|
|||
|
}
|
|||
|
private:
|
|||
|
double length; // Length of a box
|
|||
|
double breadth; // Breadth of a box
|
|||
|
double height; // Height of a box
|
|||
|
};
|
|||
|
|
|||
|
int main(void)
|
|||
|
{
|
|||
|
Box Box1(3.3, 1.2, 1.5); // Declare box1
|
|||
|
Box Box2(8.5, 6.0, 2.0); // Declare box2
|
|||
|
|
|||
|
if(Box1.compare(Box2))
|
|||
|
{
|
|||
|
cout << "Box2 is smaller than Box1" <<endl;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cout << "Box2 is equal to or larger than Box1" <<endl;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
**输出:**
|
|||
|
|
|||
|
```
|
|||
|
Constructor called.
|
|||
|
Constructor called.
|
|||
|
Box2 is equal to or larger than Box1
|
|||
|
```
|
|||
|
|
|||
|
### 指向类的指针
|
|||
|
|