引玉之砖
访问字符串中字符的一段代码:
#include <iostream>
using namespace std;
int main () {
string s = "abcd"; // 声明字符串变量,并赋值
cout << "s = " << s << endl;
cout << "s[0] = " << s[0] << endl;
cout << "s[1] = " << s[1] << endl;
cout << "s[2] = " << s[2] << endl;
cout << "s[3] = " << s[3] << endl;
cout << "s[4] = " << s[4] << endl;
// 显示了字符数组中的每一个字符,数组最后一个元素是0
return 0;
}
运行结果应该如下:
s = abcd
s[0] = a
s[1] = b
s[2] = c
s[3] = d
s[4] =
C++ 中的string
类型,本质上是一个类,并不是真正的字符串。它是对 C 风格字符串的封装。上述代码中的s
是string
类的对象。类本身并不能直接用于下标运算,那么为什么可以像上面那样访问string
中的每一个字符呢?这是因为 C++ 标准库已经为string
类重载了下标运算符,使得我们可以通过下标访问string
对象中的各个字符。
让我们再来看一段代码:
#include <iostream>
using namespace std;
class Driver
{
private:
string d_car[3];
public:
string name;
Driver() {d_car[0] = "Ferrari"; d_car[1] = "Porsche"; d_car[2] = "Tesla";}
void show() {cout << "car[0]: " << d_car[0]
<< "\ncar[1]: " << d_car[1]
<< "\ncar[2]: " << d_car[2] << endl;}
};
int main () {
Driver d;
d.show();
return 0;
}
编译运行的结果应该如下:
car[0]: Ferrari
car[1]: Porsche
car[2]: Tesla
需求:现在要访问Driver
对象d
的私有成员car
。
思路1.把car
成员设置为公有成员——不太规范。
思路2.写一个成员函数。修改后的代码如下:
#include <iostream>
using namespace std;
class Driver
{
private:
string d_car[3];
public:
string name;
Driver() {d_car[0] = "Ferrari"; d_car[1] = "Porsche"; d_car[2] = "Tesla";}
void show() {cout << "car[0]: " << d_car[0]
<< "\ncar[1]: " << d_car[1]
<< "\ncar[2]: " << d_car[2] << endl;}
string car(int num) { // 成员函数 car() 访问私有成员 d_car[]
return d_car[num];
}
};
int main () {
Driver d;
cout << "Car number 2 is a " << d.car(2) << endl;
d.show();
return 0;
}
运行结果如下:
Car number 2 is a Tesla
car[0]: Ferrari
car[1]: Porsche
car[2]: Tesla
如果函数的返回值是引用,就可以把函数调用的表达式当成变量来使用。进一步修改代码:
#include <iostream>
using namespace std;
class Driver
{
private:
string d_car[3];
public:
string name;
Driver() {d_car[0] = "Ferrari"; d_car[1] = "Porsche"; d_car[2] = "Tesla";}
void show() {cout << "car[0]: " << d_car[0]
<< "\ncar[1]: " << d_car[1]
<< "\ncar[2]: " << d_car[2] << endl;}
// 函数的返回值是引用,就可以把函数调用的表达式当成变量来使用
string& car(int num) {
return d_car[num];
}
};
int main () {
Driver d;
// 既然可以当成变量来使用,那就可以修改变量的值。
d.car(0) = "Tesla"; // 修改 d_car[0] 的值
cout << "Car number 0 is a " << d.car(0) << endl;
d.show();
return 0;
}
编译运行的结果如下:
Car number 0 is a Tesla
car[0]: Tesla
car[1]: Porsche
car[2]: Tesla
以上方法有点奇怪,更好的方法是重载下标运算符
。
重载下标运算符
仅需改动两处,代码如下:
#include <iostream>
using namespace std;
class Driver
{
private:
string d_car[3];
public:
string name;
Driver() {d_car[0] = "Ferrari"; d_car[1] = "Porsche"; d_car[2] = "Tesla";}
void show() {cout << "car[0]: " << d_car[0]
<< "\ncar[1]: " << d_car[1]
<< "\ncar[2]: " << d_car[2] << endl;}
string& operator[](int num) { // 函数名换成 operator[]
return d_car[num];
}
};
int main () {
Driver d;
d[1] = "Tesla"; // 直接改成数组下标的写法
cout << "Car number 1 is a " << d[1] << endl;
d.show();
return 0;
}
运行结果如下:
Car number 1 is a Tesla
car[0]: Ferrari
car[1]: Tesla
car[2]: Tesla
这就是下标运算符重载的效果。
string& operator[](int num) {...}
返回值类型& operator[](参数){...}
这种方法不仅可以访问数组元素,还可以修改数组元素。
第二种方法是在成员函数的前面和后面都加const
const 返回值类型& operator[](参数) const {...}
这种方法只能访问元素,不能修改元素。常对象只能访问常函数,所以还需要创建一个常对象,代码如下:
#include <iostream>
using namespace std;
class Driver
{
private:
string d_car[3];
public:
string name;
Driver() {d_car[0] = "Ferrari"; d_car[1] = "Porsche"; d_car[2] = "Tesla";}
void show() {cout << "car[0]: " << d_car[0]
<< "\ncar[1]: " << d_car[1]
<< "\ncar[2]: " << d_car[2] << endl;}
string& operator[](int num) { // 函数名换成 operator[]
return d_car[num];
}
const string& operator[](int num) const { // 函数名换成 operator[]
return d_car[num];
}
};
int main () {
Driver d;
d[1] = "Tesla"; // 直接改成数组下标的写法
cout << "Car number 1 is a " << d[1] << endl;
d.show();
const Driver d1 = d;
cout << "Car number 1 is a " << d1[1] << endl;
return 0;
}
运行效果:
Car number 1 is a Tesla
car[0]: Ferrari
car[1]: Tesla
car[2]: Tesla
Car number 1 is a Tesla
在实际开发中,应该同时提供这两种形式,这样做是为了适应const
对象,因为通过const
对象只能调用const
成员,若不提供第二种形式,那么将无法访问const
对象的任何数组元素。
感谢浏览,一起学习!