QT学习(六)C++构造函数和初始化列表
中,使用初始化列表来初始化类的字段是一种高效的初始化方式,尤其在构造函数中。初始化列表直接在对象的构造过程中初始化成员变量,而不是先创建成员变量后再赋值。:对于非基本类型的对象,使用初始化列表比在构造函数体内赋值更高效,因为它避免了先默认构造然后再赋值的额外开销。的成员变量,必须使用初始化列表,因为这些类型的成员变量在构造函数体内不能被赋值。:成员变量的初始化顺序是按照它们在类中声明的顺序,而不是
·
一·、 什么是构造函数
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造,那构造的是什么呢?
构造成员变量的初始化值,内存空间等
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于 为某些成员变量设置初始值。
下面的实例有助于更好地理解构造函数的概念:
#include <iostream>
#include <string>
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 <iostream>
#include <string>
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 <iostream>
#include <string>
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 <iostream>
#include <string>
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 <iostream>
#include <string>
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++深入讲解的课程的话,会安排到。 同理拷贝构造函数,考虑到学习策略安排,这里先陈列出来。
更多推荐


所有评论(0)