C++ 对象常见构造函数与赋值运算符

C++ 对象常见构造函数与赋值运算符

对象常见构造函数与赋值运算符如下:

  1. 普通构造函数 (Default constructor)
  2. 参数化构造函数 (Parameterized constructor)
  3. 拷贝构造函数 (Copy constructor)
  4. 拷贝赋值运算符 (Copy assignment operator)
  5. 移动构造函数 (Move constructor) (C++11引入)
  6. 移动赋值运算符 (Move assignment operator) (C++11引入)
  7. 析构函数 (Destructor)
  8. 委托构造函数(Delegating Constructor)

准备工作

创建一个标准的beanPerson

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const {
        return name;
    }
    int getAge() const {
        return age;
    }
    std::string getGender() const {
        return gender;
    }
    void setName(const std::string name) {
        this->name = name;
    }
    void setAge(const int age) {
        this->age = age;
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};

默认构造函数 (Default constructor)

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};

namespace learn01{
    void learn01(){
        Person p;
        std::cout << p << "\n";
        p.setName("lisi");
        std::cout << p << "\n";
    }
}

2. 参数化构造函数 (Parameterized constructor)

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};

namespace learn01{
    void learn01(){
        auto person = std::make_unique<Person>("Alice", 18, "女");
        std::cout << *person << std::endl;
    }
}

3. 拷贝构造函数 (Copy constructor)

拷贝构造的三种调用方式。
方式一:

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
        std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};

namespace learn01{
    void learn01(){
        Person p1("Alice", 30, "女");
        std::cout << p1 << "\n";
        Person p2 = p1; // 调用拷贝构造函数
        p2.setName("Bob");
        p2.setAge(25);
        p2.setGender("男");
        std::cout << p2 << "\n";
    }
}

方式二:

Person p2(p1); // 调用拷贝构造函数

方式三:

static void printPerson(Person person) {
    person.setName("Bob");
    person.setAge(25);
    person.setGender("男");
    std::cout << person << "\n";
}
namespace learn01{
    void learn01(){
        Person p1("Alice", 30, "女");
        printPerson(p1);
        std::cout << p1 << "\n";
    }
}

可以看到将p1参数传递给printPerson函数时进行了一次拷贝构造函数调用。
如果只是简单打印无需拷贝构造函数调用。

static void printPerson(const Person& person) {
    std::cout << person << "\n";
} 

拷贝赋值运算符 (Copy assignment operator)

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
        std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person& operator=(const Person& other){
        if(this != &other){
            name = other.name;
            age = other.age;
            gender = other.gender;
        }
        std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};
namespace learn01{
    void learn01(){
        Person p1("Alice", 30, "女");
        p1 = p1; // 自我赋值测试 // 1
        std::cout << p1 << "\n";
        Person p2 = p1; // 拷贝构造测试 // 2
        p2.setName("Bob");
        p2.setAge(25);
        p2.setGender("男");
        std::cout << p2 << "\n";
        p1 = p2; // 赋值测试
        std::cout << p1 << "\n";
    }
}

主要记得区分赋值和拷贝构造的区别。

移动构造函数

方式1

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
        std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(Person&& other) noexcept : name(std::move(other.name)), age(std::exchange(other.age, 0)), gender(std::move(other.gender)){
        std::cout << std::format("Person Move Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person& operator=(const Person& other){
        if(this != &other){
            name = other.name;
            age = other.age;
            gender = other.gender;
        }
        std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
        return *this;
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};
static void printPerson(Person p){
    std::cout << "printPerson: " << p << std::endl;
}
namespace learn01{
    void learn01(){
        Person p("Alice", 30, "女");
        std::cout << p << std::endl;
        printPerson(std::move(p)); // 1
        // printPerson(p);
        p.setName("Bob");
        p.setAge(25);
        p.setGender("男");
        std::cout << p << std::endl;
    }
}

使用移动构造函数不会触发拷贝构造函数。
方式二

namespace learn01{
    void learn01(){
        Person p("Alice", 30, "女");
        std::cout << p << std::endl;
        Person p2 = std::move(p); // 2
        p2.setName("Bob");
        p2.setAge(25);
        p2.setGender("男");
        std::cout << p << std::endl;
        std::cout << p2 << std::endl;
    }
}

方式三

namespace learn01{
    void learn01(){
        Person p("Alice", 30, "女");
        std::cout << p << std::endl;
        Person p2(std::move(p)); // 2
        p2.setName("Bob");
        p2.setAge(25);
        p2.setGender("男");
        std::cout << p << std::endl;
        std::cout << p2 << std::endl;
    }
}
  • &: 左值只的是引用
  • &&:右值指的是值
    拷贝消除(Copy Elision) 优化
Person p = Person("Alice", 30, "女");

此代码相当于直接Person p2("Bob", 25, "男");

移动赋值运算符 (Move assignment operator) (C++11引入)

作用:将临时对象(右值)的资源移动给已存在的对象。

class Person {
private:
    std::string name;
    int age;
    std::string gender;
public:
    Person() : name(""), age(0), gender(""){
        std::cout << "Person Default Constructor" << "\n";
    }
    Person(std::string name, int age, std::string gender) : name(name), age(age), gender(gender){
        std::cout << std::format("Person Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(const Person& other) : name(other.name), age(other.age), gender(other.gender){
        std::cout << std::format("Person Copy Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person(Person&& other) noexcept : name(std::move(other.name)), age(std::exchange(other.age, 0)), gender(std::move(other.gender)){
        std::cout << std::format("Person Move Constructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    ~Person(){
        std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
    }
    Person& operator=(const Person& other){
        if(this != &other){
            name = other.name;
            age = other.age;
            gender = other.gender;
        }
        std::cout << std::format("Person Copy Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
        return *this;
    }
    Person& operator=(Person&& other) noexcept {
        if(this != &other){
            name = std::move(other.name);
            age = std::exchange(other.age, 0);
            gender = std::move(other.gender);
        }
        std::cout << std::format("Person Move Assignment Operator name: {}, age: {}, gender: {}", name, age, gender) << "\n";
        return *this;   
    }
    friend std::ostream& operator<<(std::ostream& os, const Person& person) {
        os << std::format("name: {}, age: {}, gender: {}", person.name, person.age, person.gender);
        return os;
    }
    std::string getName() const { 
        return name;
    }
    int getAge() const { 
        return age;
    }
    std::string getGender() const { 
        return gender; 
    }
    void setName(const std::string name) { 
        this->name = name; 
    }
    void setAge(const int age) { 
        this->age = age; 
    }
    void setGender(const std::string gender){
        this->gender = gender;
    }
};
namespace learn01{
    void learn01(){
        Person p;
        std::cout << p << std::endl;
        p = Person("Alice", 30, "女");
        std::cout << p << std::endl;
    }
}

析构函数

~Person(){
	std::cout << std::format("Person Destructor name: {}, age: {}, gender: {}", name, age, gender) << "\n";
}

C++中使用的是RAII(Resource Acquisition Is Initialization)思想,中文常译为 "资源获取即初始化"。它是 C++ 中最核心、最重要的编程理念和设计哲学之一。
举个例子

class FileReader{
private:
    std::string filename;
    std::ifstream fileStream;
public:
    explicit FileReader(const std::string& filename) : filename(filename) {
        std::cout << "FileReader constructed for file: " << filename << std::endl;
        fileStream.open(filename);
        if (!fileStream.is_open()) {
            throw std::runtime_error("Could not open file: " + filename);
        }
    }
    ~FileReader() {
        std::cout << "FileReader destructed for file: " << filename << std::endl;
        if (fileStream.is_open()) {
            fileStream.close();
        }
    }
    void read() {
        std::string line;
        while (std::getline(fileStream, line)) {
            std::cout << line << std::endl;
        }
    }
};

namespace learn01{
    void learn01(){
        try {
            auto cores = std::thread::hardware_concurrency();
            std::cout << "Hardware concurrency (number of cores): " << cores << "\n";
            FileReader reader("D:/SoftWare/LanguageProjects/C++Projects/learn01/main.cpp");
            reader.read();
        }
        catch(const std::exception& e) {
            std::cerr << e.what() << '\n';
        }
    }
}

委托构造函数(Delegating Constructor)

Person(std::string name, int age) : Person(){
	this->name = name;
	this->age = age;
	std::cout << std::format("Person Constructor name: {}, age: {}", name, age) << "\n";
}

顾名思义将一个构造函数委托给另一个构造函数。

区分std::vectorpush_backemplace_back的区别

void learn03(){
	Person p("Bob", 30, "男");
	std::vector<Person> people;
	people.push_back(p); // 调用拷贝构造函数 // 1
	// people.emplace_back(p); // 调用拷贝构造函数 // 2
	// people.push_back(Person("Alice", 12, "女")); // 调用移动构造函数
	// people.emplace_back("Alice", 12, "女"); // 直接在容器内构造对象,避免不必要的拷贝或移动
}
  • 非临时对象push_backemplace_back效果一致
  • 临时对象优先使用emplace_back,它可以避免不必要的拷贝或移动

C++的构造函数学习完毕,有什么不足还请大家指出。
给大家推荐一C++个学校网站: C++学习网

posted @ 2025-09-06 12:01  爱情丶眨眼而去  阅读(8)  评论(0)    收藏  举报