可以将 C++ 复制构造函数用于其他目的吗?
Is it ok to use C++ copy constructor for other purpose?
其他目的,我指的是克隆。这里有一个简化的例子:我有对象,有的是正方形,有的是盒子,都是Object2D。每个人都有一个唯一的ID。
在这个系统中,我不需要对象副本的典型含义。当对象按值传递、按值返回时,会使用典型的复制构造函数……在这个系统中,每个对象都是唯一的,因此我们不需要典型的复制构造函数。两个正方形至少在 id 上会有所不同。因此,我正在使用复制构造函数来制作克隆。克隆时,我会深拷贝除id以外的树结构。
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
#include <vector>
int offset(){
return rand()%100-50;
}
int location(){
return rand()%10000-5000;
}
class Object2D{
public:
int x_, y_;
int id;
static int count;
Object2D(int x, int y):x_(x), y_(y){
id=count++;
}
};
int Object2D::count=0;
class Square: public Object2D{
public:
int getParent(){return containedBy_->id;}
Square(Object2D* containedBy, int size):
Object2D(containedBy->x_+offset(), containedBy->y_+offset()),
containedBy_(containedBy),size_(size){
std::cout<<"Square constructor"<<std::endl;
}
Square(const Square& other):
Object2D(other.x_-other.containedBy_->x_, other.y_-other.containedBy_->y_),
containedBy_(other.containedBy_), size_(other.size_){
std::cout<<"Square clone"<<std::endl;
}
private:
Object2D* containedBy_;
size_t size_;
};
class Box:public Object2D{
private:
size_t l_;size_t h_;
std::vector<std::shared_ptr<Square>> all;
public:
void addSquare(int size){
auto temp = std::make_shared<Square>(this, size);
all.push_back(std::move(temp));
}
const std::vector<std::shared_ptr<Square>>& getAll() const{
return all;
}
Box(int x, int y, size_t l, size_t h):
Object2D(x,y), l_(l), h_(h){}
Box(const Box& other):Object2D(location(), location()){// clone the other box, put cloned squares in
for(const auto& item:other.getAll()){
all.push_back(std::make_shared<Square>(*item));
}
}
void showOffsets(){
std::cout<<"show offsets of all components for container"<<id<<":";
for(const auto& item: all){
std::cout<<item->id<<"("<<item->x_-x_<<","<<item->y_-y_<<")"<<" ";
}
std::cout<<std::endl;
}
};
int main()
{
Box b(100,100,100,100);
std::cout<<"before do it"<<std::endl;
b.addSquare(10);
Box c(b);
std::cout<<b.id<<c.id<<std::endl;
b.showOffsets();
c.showOffsets();
return 0;
}
这里我克隆了一个盒子,我还需要克隆包含的方块,并保持它们的偏移量。克隆的对象将拥有新的 ID,这些 ID 都是唯一的。
问题
克隆使用复制构造函数是个好主意吗?请注意,在这种情况下,复制构造函数的行为与典型的复制构造函数不同,因此我需要禁止以任何方式调用通常预期的复制构造函数,例如我不能使用向量来包含正方形,因为一个简单的矢量擦除将调用不会保留 id 的复制构造函数。所以我使用了智能指针。
其次,为什么克隆时没有复制偏移量?这就是我想保留的东西。
结果:
before do it
Square constructor
Square clone
02
show offsets of all components for container0:1(36,33)
show offsets of all components for container2:3(-1879,2256)
是的,您可以定义自己的复制构造函数。
但是,正如您已经指出的那样,您会发现很难 "forbid" 复制您不明确需要的地方。
我的建议:给你的对象一个 clone()
函数和 delete
复制构造函数(也可能是复制运算符)。
通过这种方式,您只有在明确打算时才进行克隆。
其他目的,我指的是克隆。这里有一个简化的例子:我有对象,有的是正方形,有的是盒子,都是Object2D。每个人都有一个唯一的ID。
在这个系统中,我不需要对象副本的典型含义。当对象按值传递、按值返回时,会使用典型的复制构造函数……在这个系统中,每个对象都是唯一的,因此我们不需要典型的复制构造函数。两个正方形至少在 id 上会有所不同。因此,我正在使用复制构造函数来制作克隆。克隆时,我会深拷贝除id以外的树结构。
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
#include <vector>
int offset(){
return rand()%100-50;
}
int location(){
return rand()%10000-5000;
}
class Object2D{
public:
int x_, y_;
int id;
static int count;
Object2D(int x, int y):x_(x), y_(y){
id=count++;
}
};
int Object2D::count=0;
class Square: public Object2D{
public:
int getParent(){return containedBy_->id;}
Square(Object2D* containedBy, int size):
Object2D(containedBy->x_+offset(), containedBy->y_+offset()),
containedBy_(containedBy),size_(size){
std::cout<<"Square constructor"<<std::endl;
}
Square(const Square& other):
Object2D(other.x_-other.containedBy_->x_, other.y_-other.containedBy_->y_),
containedBy_(other.containedBy_), size_(other.size_){
std::cout<<"Square clone"<<std::endl;
}
private:
Object2D* containedBy_;
size_t size_;
};
class Box:public Object2D{
private:
size_t l_;size_t h_;
std::vector<std::shared_ptr<Square>> all;
public:
void addSquare(int size){
auto temp = std::make_shared<Square>(this, size);
all.push_back(std::move(temp));
}
const std::vector<std::shared_ptr<Square>>& getAll() const{
return all;
}
Box(int x, int y, size_t l, size_t h):
Object2D(x,y), l_(l), h_(h){}
Box(const Box& other):Object2D(location(), location()){// clone the other box, put cloned squares in
for(const auto& item:other.getAll()){
all.push_back(std::make_shared<Square>(*item));
}
}
void showOffsets(){
std::cout<<"show offsets of all components for container"<<id<<":";
for(const auto& item: all){
std::cout<<item->id<<"("<<item->x_-x_<<","<<item->y_-y_<<")"<<" ";
}
std::cout<<std::endl;
}
};
int main()
{
Box b(100,100,100,100);
std::cout<<"before do it"<<std::endl;
b.addSquare(10);
Box c(b);
std::cout<<b.id<<c.id<<std::endl;
b.showOffsets();
c.showOffsets();
return 0;
}
这里我克隆了一个盒子,我还需要克隆包含的方块,并保持它们的偏移量。克隆的对象将拥有新的 ID,这些 ID 都是唯一的。
问题
克隆使用复制构造函数是个好主意吗?请注意,在这种情况下,复制构造函数的行为与典型的复制构造函数不同,因此我需要禁止以任何方式调用通常预期的复制构造函数,例如我不能使用向量来包含正方形,因为一个简单的矢量擦除将调用不会保留 id 的复制构造函数。所以我使用了智能指针。
其次,为什么克隆时没有复制偏移量?这就是我想保留的东西。
结果:
before do it
Square constructor
Square clone
02
show offsets of all components for container0:1(36,33)
show offsets of all components for container2:3(-1879,2256)
是的,您可以定义自己的复制构造函数。
但是,正如您已经指出的那样,您会发现很难 "forbid" 复制您不明确需要的地方。
我的建议:给你的对象一个 clone()
函数和 delete
复制构造函数(也可能是复制运算符)。
通过这种方式,您只有在明确打算时才进行克隆。