QT学习(六)C++构造函数和初始化列表

一·、 什么是构造函数

类的 构造函数 是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造,那构造的是什么呢?
构造成员变量的初始化值,内存空间等
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void 。构造函数可用于 为某些成员变量设置初始值。
下面的实例有助于更好地理解构造函数的概念:
#include 
#include 
using namespace std; // 使用std命名空间
class Car {
public:
    string brand; // 不需要使用std::string
    int year;
    // 无参构造函数
    Car() {
    brand = "未知";
    year = 0;
    cout << "无参构造函数被调用" << endl; // 不需要使用std::cout和std::endl
    }
    void display() {
        cout << "Brand: " << brand << ", Year: " << year << endl;
    }
};

int main() {
    Car myCar; // 创建Car对象
    myCar.display(); // 显示车辆信息
    return 0;
}
2.7.2 带参数构造函数
默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值,如下面的例子所示:
#include 
#include 
using namespace std; // 使用std命名空间
class Car {
public:
    string brand; // 不需要使用std::string
    int year;
    // 无参构造函数
    Car(string b,int y) {
        brand=b;
        year=y;
        cout << "有参构造函数被调用" << endl; // 不需要使用std::cout和std::endl
    }
    void display() {
        cout << "Brand: " << brand << ", Year: " << year << endl;
    }
};

int main() {
    Car myCar("奥迪",2012); // 创建Car对象
    myCar.display(); // 显示车辆信息
    return 0;
}

二、使用初始化列表        

C++ 中,使用初始化列表来初始化类的字段是一种高效的初始化方式,尤其在构造函数中。初始化列表直接在对象的构造过程中初始化成员变量,而不是先创建成员变量后再赋值。这对于提高性能尤其重要,特别是在涉及到复杂对象或引用和常量成员的情况下。
初始化列表紧跟在构造函数参数列表后面,以冒号( : )开始,后跟一个或多个初始化表达式,每个表达式通常用逗号分隔。下面是使用初始化列表初始化字段的例子:
#include 
#include 
using namespace std; // 使用std命名空间
class Car {
public:
    string brand; // 不需要使用std::string
    int year;
    // 参数列表构造函数
    Car(string b,int y) : brand(b),year(y) {
        cout << "参数列表构造函数被调用" << endl; // 不需要使用std::cout和std::endl
    }
    void display() {
        cout << "Brand: " << brand << ", Year: " << year << endl;
    }
};

int main() {
    Car myCar("奥迪",2012); // 创建Car对象
    myCar.display(); // 显示车辆信息
    return 0;
}

在这个例子中, myCar 有三个成员变量: brand int 类型)、 year( double 类型)。当创建 myCar的一个实例时,我们通过构造函数传递三个参数,这些参数

被用于通过初始化列表直接初始化成员变量。初始化列表 : brand(x), year(y)的意思是用 x 初始化

brand ,用 y 初始化 year    
初始化列表的优点包括:
1. 效率 :对于非基本类型的对象,使用初始化列表比在构造函数体内赋值更高效,因为它避免了先默认构造然后再赋值的额外开销。
2. 必要性 :对于 引用类型和常量类型 的成员变量,必须使用初始化列表,因为这些类型的成员变量在构造函数体内不能被赋值。
3. 顺序 :成员变量的初始化顺序是按照它们在类中声明的顺序,而不是初始化列表中的顺序。
使用初始化列表是 C++ 中推荐的初始化类成员变量的方式,因为它提供了更好的性能和灵活性。

三、new关键字

C++ 中, new 关键字用于动态分配内存。它是 C++ 中处理动态内存分配的主要工具之一,允许在程序运行时根据需要分配内存。
基本用法
分配单个对象 :使用 new 可以在堆上动态分配一个对象。例如, new int 会分配一个 int 类型的空
间,并返回一个指向该空间的指针。
int* ptr = new int ; //C 语言中, int *p = (int *)malloc(sizeof(int));
分配对象数组 new 也可以用来分配一个对象数组。例如, new int[10] 会分配一个包含 10 个整数的数组。
int* arr = new int [ 10 ]; //C 语言中, int *arr = (int *)malloc(sizeof(int)*10);
初始化 :可以在 new 表达式中使用初始化。对于单个对象,可以使用构造函数的参数:
MyClass * obj = new MyClass ( arg1 , arg2 );
delete 配对使用
使用 new 分配的内存必须显式地通过 delete (对于单个对象)或 delete[] (对于数组)来释放,以避免内存泄露:
释放单个对象:
delete ptr ; // 释放 ptr 指向的对象
释放数组:
delete [] arr ; // 释放 arr 指向的数组
注意事项
异常安全 :如果 new 分配内存失败,它会抛出 std::bad_alloc 异常(除非使用了 nothrow
本)。
内存泄露 :忘记释放使用 new 分配的内存会导致内存泄露。
匹配使用 delete delete[] :为避免未定义行为,使用 new 分配的单个对象应该使用
delete 释放,使用 new[] 分配的数组应该使用 delete[] 释放。
示例代码
#include 
#include 
class MyClass {
public:
    MyClass() {
    std::cout << "Object created" << std::endl;
    }
};
 int main() {
    // 分配单个对象
    MyClass* myObject = new MyClass();
    // 分配对象数组
    int* myArray = new int[5]{1, 2, 3, 4, 5};
    // 使用对象和数组...
    // 释放内存
    delete myObject;
    delete[] myArray;
    
    return 0;
}
在这个例子中, new 被用来分配一个 MyClass 类型的对象和一个整数数组,然后使用 delete
delete[] 来释放内存。每个 new 都对应一个 delete ,保证了动态分配的内存被适当管理。
四、 析构函数

(1)什么是析构函数

析构函数是 C++ 中的一个特殊的成员函数,它在对象生命周期结束时被自动调用,用于执行对象销毁前的清理工作。析构函数特别重要,尤其是在涉及动态分配的资源(如内存、文件句柄、网络连接等)的情况下。

(2)基本特性

1. 名称 :析构函数的名称由波浪号( ~ )后跟类名构成,如 ~MyClass()
2. 无返回值和参数 :析构函数不接受任何参数,也不返回任何值。
3. 自动调用 :当对象的生命周期结束时(例如,一个局部对象的作用域结束,或者使用 delete 删除一个动态分配的对象),析构函数会被自动调用。
4. 不可重载 :每个类只能有一个析构函数。
5. 继承和多态 :如果一个类是多态基类,其析构函数应该是虚的。
示例
假设我们有一个类 MyClass ,它包含了动态分配的内存或其他资源:
#include 
#include 

class MyClass {
private:
    int *datas;
public:
    MyClass(int size) {
        datas = new int[size];
    }
    ~MyClass() {
        std::cout << "析构函数执行" << std::endl;
        delete[] datas;
    }
};
 int main() {
    // 分配单个对象
    MyClass m1(10);
    MyClass* m2 = new MyClass(10);
    delete m2;

    return 0;
}

在这个示例中, MyClass 的构造函数分配了一块内存,而析构函数释放了这块内存。当 obj 的生命周期结束时(即离开了它的作用域), MyClass 的析构函数被自动调用,负责清理资源,防止内存泄露。

(3)重要性

析构函数在管理资源方面非常重要。没有正确实现析构函数,可能导致资源泄露或其他问题。在基于 RAII (资源获取即初始化)原则的C++ 编程实践中,确保资源在对象析构时被适当释放是非常关键的。当使用
智能指针和其他自动资源管理技术时,可以减少显式编写析构函数的需要,但了解析构函数的工作原理 仍然很重要。
以下是关于 C++ 中析构函数需要了解的十个要点的表格:
标注粗体部分,是能快速上手的内容,方便后续 QT 的学习,而没有粗体的部分,会在 QT 结束后,如果安 排C++ 深入讲解的课程的话,会安排到。 同理拷贝构造函数,考虑到学习策略安排,这里先陈列出来。
QT学习(六)C++构造函数和初始化列表_第1张图片
QT学习(六)C++构造函数和初始化列表_第2张图片

你可能感兴趣的:(qt,开发语言,qt,c++,学习)