下面是“C++拷贝构造函数防篡改示例”的完整攻略。
标准拷贝构造函数
在开始介绍防篡改示例之前,我们先来了解一下C++中的标准拷贝构造函数。拷贝构造函数是一种特殊的构造函数,它用来复制同类对象。当我们不定义一个类的拷贝构造函数时,编译器会自动生成一个默认的拷贝构造函数。这个默认构造函数完成的是浅复制,即将一个对象的数据成员复制到另一个对象中,这两个对象指向的数据成员是同一片内存空间。这种复制方式在某些情况下会引发一些问题,如多个对象共享同一块内存,当一个对象修改该内存时会影响到其他对象。
下面是一个简单的示例,演示了浅拷贝的问题:
#include <iostream>
using namespace std;
class MyString {
public:
char* str; // 字符串指针
// 构造函数
MyString(const char* s = "") {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// 默认拷贝构造函数
// 即:MyString(const MyString& obj) {}
};
int main() {
MyString str1("hello");
MyString str2(str1);
str1.str[0] = 'H';
cout << str1.str << endl; // 输出Hello
cout << str2.str << endl; // 输出Hello
return 0;
}
在上面的示例中,我们定义了一个MyString类,它有一个char指针成员变量,表示一个字符串。我们没有定义自己的拷贝构造函数,所以编译器会生成一个默认的拷贝构造函数,即完成浅复制。在main函数中,我们先构造一个字符串“hello”的对象str1,然后又用str1来拷贝构造一个新的对象str2。接着我们修改了str1所指向的字符串的第一个字符为大写字母H。然后分别输出str1和str2所指向的字符串,发现它们的值都变成了Hello。这是因为它们指向的是同一块内存空间,所以一个对象的修改会影响到另一个对象。
防篡改的拷贝构造函数
为了解决这个问题,我们需要自己实现一个拷贝构造函数,完成深复制,即将一个字符串复制到新的内存空间中,两个对象的数据成员不再指向同一个内存空间。为了防止被篡改,我们可以使用const修饰符,使得拷贝构造函数不能修改原对象的值。
下面是一个示例,演示了如何实现深拷贝的拷贝构造函数,并使用了const修饰符:
#include <iostream>
using namespace std;
class MyString {
public:
char* str; // 字符串指针
// 构造函数
MyString(const char* s = "") {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// 拷贝构造函数
MyString(const MyString& obj) {
str = new char[strlen(obj.str) + 1];
strcpy(str, obj.str);
}
// 析构函数
~MyString() {
delete[] str;
}
// 输出字符串
void print() const {
cout << str << endl;
}
};
int main() {
MyString str1("hello");
MyString str2(str1);
str1.str[0] = 'H';
str1.print(); // 输出Hello
str2.print(); // 输出hello
return 0;
}
在上面的示例中,我们重载了MyString的拷贝构造函数,在拷贝构造函数中,我们遵循深复制的原则,将原对象的数据成员复制到新的内存空间中。在定义拷贝构造函数的时候使用了const关键字,使得拷贝构造函数不能修改原对象的值。这样,即使我们修改了原对象的值,由于新构造的对象指向的内存空间隔离,不会被篡改。在main函数中,我们修改了str1所指向的字符串的第一个字符为大写字母H。接着分别输出str1和str2所指向的字符串,发现它们的值已经不同了,一个是Hello,另一个是hello。
示例1:防篡改的拷贝构造函数 + 模板类
下面我们再演示一个实际应用的示例,在这个示例中,我们定义了一个用于管理日志的MyLogger类,这个类是一个模板类,支持多种类型的日志。由于日志的内容是敏感信息,我们不能让多个MyLogger对象共享同一块内存,所以我们需要实现深拷贝的拷贝构造函数。此外,由于MyLogger是一个模板类,我们需要在类定义的外部实现拷贝构造函数,所以我们将拷贝构造函数声明为友元函数。
#include <iostream>
#include <cstring>
using namespace std;
template<typename T>
class MyLogger {
public:
T* data; // 日志数据
int len; // 日志长度
// 构造函数
MyLogger(const T* d = "", int l = 0) {
len = l;
data = new T[len];
memcpy(data, d, len * sizeof(T));
}
// 友元拷贝构造函数
friend MyLogger<T>::MyLogger(const MyLogger& obj) {
len = obj.len;
data = new T[len];
memcpy(data, obj.data, len * sizeof(T));
}
// 析构函数
~MyLogger() {
delete[] data;
}
// 输出日志
void print() const {
for (int i = 0; i < len; i++) {
cout << data[i] << " ";
}
cout << endl;
}
};
int main() {
int arr1[] = {1,2,3,4};
MyLogger<int> logger1(arr1, 4);
MyLogger<int> logger2(logger1);
arr1[0] = 10; // 修改原始数据
logger1.print(); // 输出 10 2 3 4
logger2.print(); // 输出 1 2 3 4
double arr2[] = {3.14, 1.618};
MyLogger<double> logger3(arr2, 2);
MyLogger<double> logger4(logger3);
arr2[0] = 2.718; // 修改原始数据
logger3.print(); // 输出 2.718 1.618
logger4.print(); // 输出 3.14 1.618
return 0;
}
在上面的示例中,我们定义了一个MyLogger模板类,它有一个模板参数T。MyLogger类中有一个data指针成员变量表示日志数据,还有一个len成员变量表示日志长度。MyLogger类的构造函数和析构函数分别完成了对象的创建和销毁。拷贝构造函数声明为一个友元函数,在类定义的外部实现。在拷贝构造函数中,我们沿用了示例2中的方式,实现了深复制。在main函数中,我们定义了两个MyLogger
示例2:拷贝构造函数用于防止动态数组的浅复制
下面再演示一个实际应用的示例,这个例子展示了如何使用拷贝构造函数防止动态数组的浅复制。在这个示例中,我们定义了一个IntVector类,它是一个动态数组类型,支持自动扩容,可以将整数不断添加到数组中。在IntVector类中,我们重载了拷贝构造函数,使得对象之间的复制不再是浅复制,而是深复制。这样,即使数组中的值被修改,也不会影响到其他对象和它们的数组。
#include <iostream>
using namespace std;
class IntVector {
private:
int* data; // 数据指针
int capacity; // 当前容量
int length; // 当前长度
public:
// 构造函数
IntVector() {
capacity = 10;
length = 0;
data = new int[capacity];
}
// 拷贝构造函数,进行深复制
IntVector(const IntVector& obj) {
capacity = obj.capacity;
length = obj.length;
data = new int[capacity];
for (int i = 0; i < length; i++) {
data[i] = obj.data[i];
}
}
// 析构函数
~IntVector() {
delete[] data;
}
// 添加元素
void push_back(int value) {
if (length >= capacity) {
int* old_data = data;
data = new int[2 * capacity];
for (int i = 0; i < length; i++) {
data[i] = old_data[i];
}
capacity *= 2;
delete[] old_data;
}
data[length++] = value;
}
// 输出数组
void print() const {
for (int i = 0; i < length; i++) {
cout << data[i] << " ";
}
cout << endl;
}
};
int main() {
IntVector vec1;
vec1.push_back(1);
vec1.push_back(2);
vec1.push_back(3);
IntVector vec2(vec1);
vec1.push_back(4);
vec2.print(); // 输出1 2 3
return 0;
}
在上面的示例中,我们定义了一个IntVector类,它有一个data指针成员变量表示动态数组,还有一个capacity成员变量表示当前容量,和一个length成员变量表示当前长度。IntVector类的构造函数和析构函数分别完成了对象的创建和销毁。拷贝构造函数重载了标准的拷贝构造函数,进行深复制。在main函数中,我们定义了两个IntVector对象vec1和vec2,然后向vec1中添加了一些整数,然后将vec1拷贝到vec2中。接着我们向vec1中再添加了一个元素4,然后输出vec2的值,发现没有被修改,依旧是1 2 3。这说明我们的拷贝构造函数实现正确,确实起到了防止浅复制的作用。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++拷贝构造函数防篡改示例 - Python技术站