共享数据的保护
对于既需要共享、又需要防止改变的数据应该声明为常类型(用const进行修饰)。
对于不改变对象状态的成员函数应该声明为常函数。
常对象
在C++中,常对象(constant objects)是使用 const
关键字修饰的对象,其值在初始化后不能被修改。常对象通常用于表示不可变的数据,提高代码的安全性和可读性。对于常对象,有以下几点需要注意:
1. 定义常对象
定义常对象时,需要在对象声明时使用 const
关键字。常对象只能调用常量成员函数。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
void setData(int val) {
data = val;
}
int getData() const {
return data;
}
};
int main() {
const MyClass obj(10); // 定义常对象
cout << "Data: " << obj.getData() << endl;
// obj.setData(20); // 错误:不能调用非常量成员函数
return 0;
}
在上面的示例中,obj
被声明为常对象,因此它只能调用 getData
这样的常量成员函数,而不能调用 setData
这样的非常量成员函数。
2. 常对象的成员函数
常对象只能调用常量成员函数。常量成员函数是在成员函数的声明和定义后面加上 const
关键字,以表示该成员函数不会修改对象的状态。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
void setData(int val) {
data = val;
}
int getData() const {
return data;
}
void display() const {
cout << "Data: " << data << endl;
}
};
int main() {
const MyClass obj(10);
obj.display(); // 调用常量成员函数
return 0;
}
3. 常对象的成员变量
常对象的成员变量在初始化后不能被修改。因此,只有常量成员函数可以被常对象调用。
#include <iostream>
using namespace std;
class MyClass {
private:
const int data;
public:
MyClass(int val) : data(val) {}
int getData() const {
return data;
}
void display() const {
cout << "Data: " << data << endl;
}
};
int main() {
const MyClass obj(10);
obj.display();
return 0;
}
在上面的示例中,data
被声明为 const
,表示它是一个常量成员变量。这个变量只能在初始化列表中赋值,之后不能被修改。
4. 常对象和指针
常对象可以通过指针和引用访问。可以声明指向常对象的指针和引用,以确保指针和引用指向的对象不能被修改。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
int getData() const {
return data;
}
};
int main() {
MyClass obj(10);
const MyClass* ptr = &obj; // 指向常对象的指针
cout << "Data: " << ptr->getData() << endl;
// ptr->setData(20); // 错误:不能通过指向常对象的指针修改值
const MyClass& ref = obj; // 指向常对象的引用
cout << "Data: " << ref.getData() << endl;
// ref.setData(20); // 错误:不能通过指向常对象的引用修改值
return 0;
}
总结
常对象在C++中提供了一种机制,用于定义不可变的数据,提高代码的安全性和可读性。常对象只能调用常量成员函数,不能修改对象的状态。通过合理使用常对象,可以防止意外修改数据,提高代码的稳定性和可维护性。
常成员
在C++中,常成员(const member)是指使用 const
关键字修饰的类成员,它们的值在初始化后不能被修改。常成员可以是成员变量,也可以是成员函数。使用常成员可以提高代码的安全性和可读性,防止意外修改数据。
1. 常成员变量
常成员变量是在类定义中使用 const
关键字修饰的成员变量。常成员变量必须在初始化列表中进行初始化,因为它们的值在对象创建后不能被修改。
#include <iostream>
using namespace std;
class MyClass {
private:
const int data;
public:
MyClass(int val) : data(val) {} // 使用初始化列表初始化常成员变量
int getData() const {
return data;
}
};
int main() {
MyClass obj(10);
cout << "Data: " << obj.getData() << endl;
// obj.data = 20; // 错误:不能修改常成员变量的值
return 0;
}
在上面的示例中,data
被声明为 const
,表示它是一个常成员变量。它必须在构造函数的初始化列表中进行初始化,并且在对象的生命周期内不能被修改。
2. 常成员函数
常成员函数是在成员函数的声明和定义后面加上 const
关键字,以表示该成员函数不会修改对象的状态(即不会修改成员变量的值)。常成员函数可以被常对象调用,而非常成员函数不能被常对象调用。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
void setData(int val) {
data = val;
}
int getData() const { // 常成员函数
return data;
}
};
int main() {
const MyClass obj(10); // 常对象
cout << "Data: " << obj.getData() << endl;
// obj.setData(20); // 错误:不能调用非常量成员函数
return 0;
}
在上面的示例中,getData
被声明为常成员函数,因此它可以被常对象 obj
调用,而 setData
不能被常对象调用。
3. 常成员函数的实现
常成员函数的实现和声明一样,需要在函数定义后面加上 const
关键字。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
void setData(int val) {
data = val;
}
int getData() const; // 常成员函数声明
};
int MyClass::getData() const { // 常成员函数定义
return data;
}
int main() {
const MyClass obj(10);
cout << "Data: " << obj.getData() << endl;
return 0;
}
4. 常成员函数与非常成员函数的重载
C++允许同名的成员函数根据是否是常成员函数进行重载。这意味着可以有两个同名的成员函数,一个是常成员函数,一个是非常成员函数。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
int getData() const { // 常成员函数
return data;
}
int getData() { // 非常成员函数
return data + 1;
}
};
int main() {
const MyClass obj1(10);
MyClass obj2(20);
cout << "Data (const object): " << obj1.getData() << endl; // 调用常成员函数
cout << "Data (non-const object): " << obj2.getData() << endl; // 调用非常成员函数
return 0;
}
在上面的示例中,getData
有两个版本,一个是常成员函数,一个是非常成员函数。当常对象 obj1
调用 getData
时,调用的是常成员函数。当非常对象 obj2
调用 getData
时,调用的是非常成员函数。
总结
常成员变量和常成员函数在C++中提供了一种机制,用于定义不可变的数据和保证成员函数不修改对象状态。通过合理使用常成员,可以提高代码的安全性和可读性,防止意外修改数据,并使代码更易于维护。
常引用
在C++中,常引用(constant reference)是指使用 const
关键字修饰的引用。常引用的特点是不能通过该引用修改所引用的变量的值。常引用通常用于函数参数和返回值,以提高程序的安全性和效率,特别是在处理大型对象时。下面详细介绍常引用的使用和示例。
1. 定义常引用
常引用是在引用声明时使用 const
关键字修饰的引用。常引用不能用于修改其所引用的变量。
#include <iostream>
using namespace std;
int main() {
int x = 10;
const int& ref = x; // 定义常引用
cout << "Value of x: " << ref << endl;
// ref = 20; // 错误:不能通过常引用修改值
x = 20; // 可以直接修改原变量的值
cout << "Value of x: " << ref << endl;
return 0;
}
在上面的示例中,ref
是一个常引用,它引用变量 x
的值,但不能通过 ref
修改 x
的值。
2. 常引用作为函数参数
常引用常用于函数参数,以避免拷贝大型对象,提高效率,并防止函数内部修改传入的参数。
#include <iostream>
using namespace std;
void printValue(const int& val) {
cout << "Value: " << val << endl;
// val = 20; // 错误:不能通过常引用修改值
}
int main() {
int a = 10;
printValue(a);
return 0;
}
在上面的示例中,函数 printValue
接受一个常引用参数 val
,它不能在函数内部修改 val
的值。
3. 常引用作为函数返回值
常引用也可以作为函数的返回值,以提高效率并防止调用者修改返回值。
#include <iostream>
using namespace std;
class MyClass {
private:
int data;
public:
MyClass(int val) : data(val) {}
const int& getData() const {
return data;
}
};
int main() {
MyClass obj(10);
const int& ref = obj.getData(); // 使用常引用接收返回值
cout << "Data: " << ref << endl;
// ref = 20; // 错误:不能通过常引用修改值
return 0;
}
在上面的示例中,getData
函数返回一个常引用,使得调用者不能修改返回的值。
4. 常引用与临时对象
常引用还可以绑定到临时对象。这是因为临时对象的生命周期在常引用的作用范围内得到了延长。
#include <iostream>
using namespace std;
const int& getTemporaryValue() {
return 42; // 返回临时对象
}
int main() {
const int& ref = getTemporaryValue(); // 常引用绑定到临时对象
cout << "Temporary value: " << ref << endl;
return 0;
}
在上面的示例中,ref
绑定到函数 getTemporaryValue
返回的临时对象,并且其生命周期在 ref
的作用范围内得到了延长。
5. 常引用与指针
常引用还可以与指针结合使用,以确保指针指向的对象不能被修改。
#include <iostream>
using namespace std;
void printValue(const int* const ptr) {
cout << "Value: " << *ptr << endl;
// *ptr = 20; // 错误:不能通过常指针修改值
}
int main() {
int x = 10;
printValue(&x);
return 0;
}
在上面的示例中,函数 printValue
接受一个常指针参数 ptr
,确保指针指向的对象不能被修改。
总结
常引用在C++中提供了一种机制,用于提高程序的安全性和效率。通过常引用,可以防止通过引用修改原始数据,特别是在处理大型对象和临时对象时。此外,常引用可以用于函数参数和返回值,以提高函数的效率和安全性。