星期六我参加了考试,我查看过去的论文,并且根据C ++代码我遇到过问题:
class Car {
char *LicencePlate;
int age;
public:
Car(const Car &); //this declaration
~Car();
}
第5行声明的目的是什么?一般来说,实施这种性质的声明应该提供哪些功能?在第5行写下声明实现所需的代码,如同提供的信息一样,它将出现在Car.cpp
文件中。
答案 0 :(得分:9)
让我们来看看。
从名称可以看出,这是一个构造函数。因为它需要一个参数引用相同类型的对象,所以它是复制构造函数(C ++命名法)。
如您所知(或不知道),如果您没有复制构造函数,编译器将为您生成一个。编译器生成的复制构造函数执行浅复制。
class Car {
char *LicencePlate;
public:
Car(char* plate, int size)
{
LicencePlate = new char[size];
strcpy(LicencePlate, plate);
}
~Car()
{
delete[] LicencePlate;
}
};
我已经修改了你的课程以便更好地解释。你的班级现在管理记忆。它为LicencePlate
分配内存。这是您没有复制构造函数的情况。说你做:
Car a("abc",3);
使用以下命令调用编译器生成的复制构造函数。
Car b(a);
但请记住,这只是一个浅拷贝。实际上,a.LicencePlate == b.LicencePlate
。 你能看到有什么问题吗?
当a
超出范围时,将调用析构函数,并删除a.LicencePlate
。但是当b
超出范围时,你会遇到未定义的行为,因为b
的析构函数将尝试删除相同的内存(记住,两个指针指向同一个内存,因为浅副本是创建)。
为避免这种情况,您可以定义自己的复制构造函数:
class Car {
char *LicencePlate;
int sz;
public:
Car(char* plate, int size)
{
LicencePlate = new char[size+1]();
strcpy(LicencePlate, plate);
sz = size;
}
Car(const Car& other)
{
LicencePlate = new char[other.sz+1]();
sz = other.sz;
strcpy(LicencePlate, other.LicencePlate);
}
~Car()
{
delete[] LicencePlate;
}
};
三个规则意味着你应该实现一个赋值运算符(你已经有了一个复制构造函数和一个析构函数)。这背后的动机是相同的,只有当你分配而不是初始化时问题才会复制:
Car a("abc",3);
Car b;
b = a; //assignment - operator= is called
现在我们很安全。复制时b
将分配新内存来保存车牌,因此不能进行双重删除。
我更改了代码以证明这一点,但你仍然必须自己将逻辑放在那里。
答案 1 :(得分:8)
它是一个复制构造函数,它的目的是制作作为参数给出的对象的精确副本。
我会留给你决定如何最好地做到这一点。
答案 2 :(得分:2)
这是一个复制构造函数声明。它需要引用常量Car
,这意味着你可以读取传入的值,但不能(没有狡猾的强制转换)写入它。这只是通过复制原始文件来创建新对象的规范方法。您可能希望在实施过程中执行strdup
。
答案 3 :(得分:0)
声明称为复制构造函数。通常,复制构造函数用于为类构造给定实例的新实例。
在签名中:
Car(const Car &)
“const”表示无法在方法中修改传递的实例。 “&安培;”意味着实例通过引用传递给方法。在没有“&”的情况下传入一个类的实例(按值传递)将使用复制构造函数创建类的新实例。在声明复制构造函数的情况下,通过值传递不仅会自我失败,而且会导致复制构造函数被递归调用,直到遇到堆栈溢出。
进入cpp文件的代码应该是传入的实例的可接受副本。可以根据用户场景采用合理的方式。
答案 4 :(得分:-3)
我假设你的意思是第5行,然后是
Car(const Car &);
是一个构造函数,其唯一参数是对另一个Car对象的引用。它标记为const表示构造函数不应该修改给定的汽车。由于它是一个引用,你需要检查以确保你没有以某种方式引用正在构造的同一个对象:
if (this==car){
return;
}
或类似的东西。