vector<Class> --- 关于 Class 中的复制构造函数的问题

vector<Class> --- Question about Copy Constructor in Class

更新:抱歉,如果我有这样的问题打扰别人。我今年 48 岁。我正在努力找一份新的职业来谋生。我只需要“做这个”的信息。不要那样做。永远不要问为什么。 :) 感谢大家对 me_kind 人的回答和耐心 :)

我有Class辆车。

class Car {
protected:
    std::string Name;
    short Year;
    float Engine;
    float Price;
public:
Car() {
    Name = "ordinary";
    Year = 1980;
    Engine = 2.0;
    Price = 1000.;
}
Car(std::string name, short year, float engine, float price) {
    Name = name;
    Year = year;
    Engine = engine;
    Price = price;
}
Car(Car& other) {
    this->Name = other.Name;
    this->Year = other.Year;
    this->Engine = other.Engine;
    this->Price = other.Price;
}
Car(Car&& other) {
    this->Name = other.Name;
    this->Year = other.Year;
    this->Engine = other.Engine;
    this->Price = other.Price;
}
void operator= (Car& other) {
    this->Name = other.Name;
    this->Year = other.Year;
    this->Engine = other.Engine;
    this->Price = other.Price;
}

inline std::string GetName() const { return Name; }
inline short GetYear() const { return Year; }
inline float GetEngine() const { return Engine; }
inline float GetPrice() const { return Price; }
inline void SetName(std::string n) { Name = n; }
inline void SetYear(short y) { Year = y; }
inline void SetEngine(float e) { Engine = e; }
inline void SetPrice(float p) { Price = p; }
void InitCar(std::string name, short year, float engine, float price) {
    Name = name;
    Year = year;
    Engine = engine;
    Price = price;
}
void ShowCar() {
    std::cout << "Car_Name: " << Name << ";\nYear: " << Year
        << "; Engine: " << Engine << "; Price: " << Price << "\n";
    }
};

然后我创建 Car 对象的向量。

std::vector<Car> base;

现在

base.push_back(Car());

这对编译器来说没问题。 接下来也可以:

base.push_back(Car("this_car", 1900, 1.5, 1000));

但是下一个不行:

Car car("that_car", 2001, 3.0, 3000);
base.push_back(car);

编译器说:

no copy constructor available

当我从 Class 汽车中获取 Copy Constructor 时,一切正常。

谁能解释为什么我应该从 Car 中删除 Copy Constructor class?

感谢大家的帮助和耐心。

你应该为复制构造函数参数指定const

Car(const Car& other) {
    this->Name = other.Name;
    this->Year = other.Year;
    this->Engine = other.Engine;
    this->Price = other.Price;
}

复制构造函数的正确声明应该是:

Car(const Car& other)

与复制赋值运算符相同,它也需要 Car& 的 return 值:

Car& operator= (const Car& other)
{
    ...
    return *this;
}

此外,您的移动构造函数实现不正确。它是复制 Name 成员,而不是移动 它。它应该看起来像这样:

Car(Car&& other) {
    this->Name = std::move(other.Name);
    this->Year = other.Year; other.Year = 0;
    this->Engine = other.Engine; other.Engine = 0;
    this->Price = other.Price; other.Price = 0;
}

并且您需要添加移动赋值运算符:

Car& operator= (Car&& other) {
    this->Name = std::move(other.Name);
    this->Year = other.Year; other.Year = 0;
    this->Engine = other.Engine; other.Engine = 0;
    this->Price = other.Price; other.Price = 0;
    return *this;
}

在这种情况下,复制赋值和移动赋值运算符都可以实现为分别使用复制构造函数和移动构造函数(参见What is the copy-and-swap idiom?):

Car& operator= (const Car& other) {
    Car temp(other);
    std::swap(this->Name, temp.Name);
    this->Year = temp.Year;
    this->Engine = temp.Engine;
    this->Price = temp.Price;
    return *this;
}

Car& operator= (Car&& other) {
    Car temp(std::move(other));
    std::swap(this->Name, temp.Name);
    this->Year = temp.Year;
    this->Engine = temp.Engine;
    this->Price = temp.Price;
    return *this;
}

在这种情况下,您可以通过按值而不是按引用传递参数,将复制赋值和移动赋值运算符组合到一个实现中,从而允许调用者决定是使用复制还是移动语义:

Car& operator= (Car other) {
    std::swap(this->Name, other.Name);
    this->Year = other.Year;
    this->Engine = other.Engine;
    this->Price = other.Price;
    return *this;
}

也就是说,由于 std::string 已经实现了正确的复制和移动语义,您应该让编译器为您生成 copy/move-constructors 和 copy/move-assignment 运算符的默认实现:

class Car {
protected:
    std::string Name;
    short Year;
    float Engine;
    float Price;
public:
    Car() : Car("ordinary", 1980, 2.0, 1000)
    {
    }

    Car(std::string name, short year, float engine, float price)
        : Name(name), Year(year), Engine(engine), Price(price)
    {
    }

    Car(const Car&) = default;
    Car(Car&& other) = default;

    Car& operator= (const Car&) = default;
    Car& operator= (Car&&) = default;

    ...
};