C++复杂类对象初始化的方法
·
一个复杂的类,定义其对象时可能有多种初始化的方法,不仅他们之间很容易搞混,还容易和先定义再赋值的一些情况混淆,本节我们详细列举常遇到的初始化方式,用于区分学习。
几种常用初始化方式:
先强调一下:任何类一定要自主设置构造函数,一定不能使用系统自带的默认构造函数,因为成员变量会被赋危险不可知的值。
可行:
1.无参初始化 - 调用无参构造函数(内部用初始化列表处理),这是自行设置默认构造函数。
2.直接初始化 - 使用构造函数参数
3.拷贝初始化 - 使用等号和已有对象
4.列表初始化 - C++11引入的花括号语法
5.值初始化 - 使用空花括号
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
class ComplexClass {
private:
int id;
std::string name;
std::vector<int> data;
double* values;
size_t size;
public:
// 无参构造函数
ComplexClass() : id(0), name("Default"), values(nullptr), size(0) {
std::cout << "Default constructor called" << std::endl;
}
// 参数化构造函数
ComplexClass(int id, const std::string& name, std::initializer_list<int> list)
: id(id), name(name), data(list), size(list.size()) {
values = new double[size];
for (size_t i = 0; i < size; ++i) {
values[i] = i * 1.1;
}
std::cout << "Parameterized constructor called" << std::endl;
}
// 拷贝构造函数
ComplexClass(const ComplexClass& other)
: id(other.id), name(other.name), data(other.data), size(other.size) {
values = new double[size];
for (size_t i = 0; i < size; ++i) {
values[i] = other.values[i];
}
std::cout << "Copy constructor called" << std::endl;
}
// 拷贝赋值运算符
ComplexClass& operator=(const ComplexClass& other) {
if (this != &other) {
delete[] values;
id = other.id;
name = other.name;
data = other.data;
size = other.size;
values = new double[size];
for (size_t i = 0; i < size; ++i) {
values[i] = other.values[i];
}
}
std::cout << "Copy assignment operator called" << std::endl;
return *this;
}
// 析构函数
~ComplexClass() {
delete[] values;
std::cout << "Destructor called for ID: " << id << std::endl;
}
// 显示对象内容
void display() const {
std::cout << "ID: " << id << ", Name: " << name << std::endl;
std::cout << "Data: ";
for (int num : data) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << "Values: ";
for (size_t i = 0; i < size; ++i) {
std::cout << values[i] << " ";
}
std::cout << std::endl << std::endl;
}
// 设置ID
void setId(int newId) {
id = newId;
}
// 设置名称
void setName(const std::string& newName) {
name = newName;
}
};
int main() {
std::cout << "=== C++ 对象初始化与赋值示例 ===" << std::endl << std::endl;
// 1. 无参初始化
std::cout << "1. 无参初始化:" << std::endl;
ComplexClass obj1;
obj1.display();
// 2. 直接初始化(使用构造函数)
std::cout << "2. 直接初始化:" << std::endl;
ComplexClass obj2(101, "DirectInit", {1, 2, 3, 4, 5});
obj2.display();
// 3. 拷贝初始化
std::cout << "3. 拷贝初始化:" << std::endl;
ComplexClass obj3 = obj2;
obj3.setId(102);
obj3.setName("CopyInit");
obj3.display();
// 4. 列表初始化
std::cout << "4. 列表初始化:" << std::endl;
ComplexClass obj4{103, "ListInit", {6, 7, 8, 9}};
obj4.display();
// 5. 值初始化
std::cout << "5. 值初始化:" << std::endl;
ComplexClass obj5{};
obj5.setId(104);
obj5.setName("ValueInit");
obj5.display();
std::cout << "=== 程序结束,自动调用析构函数 ===" << std::endl;
return 0;
}
区分初始化和赋值
一般来说,等号在声明中通常表示初始化,而在语句中(对象已存在)表示赋值。
#include <iostream>
#include <string>
class MyClass {
private:
int value;
std::string name;
public:
// 默认构造函数
MyClass() : value(0), name("Default") {
std::cout << "默认构造函数" << std::endl;
}
// 参数化构造函数
MyClass(int v, const std::string& n) : value(v), name(n) {
std::cout << "参数化构造函数: " << name << std::endl;
}
// 拷贝构造函数
MyClass(const MyClass& other) : value(other.value), name(other.name + "_copy") {
std::cout << "拷贝构造函数: " << name << std::endl;
}
// 拷贝赋值运算符
MyClass& operator=(const MyClass& other) {
value = other.value;
name = other.name + "_assigned";
std::cout << "拷贝赋值运算符: " << name << std::endl;
return *this;
}
void display() const {
std::cout << "Value: " << value << ", Name: " << name << std::endl;
}
};
int main() {
std::cout << "=== 等于号作为初始化 ===" << std::endl;
// 情况1: 声明时的等于号是初始化(拷贝初始化)
std::cout << "\n1. 拷贝初始化:" << std::endl;
MyClass obj1(10, "Original");
MyClass obj2 = obj1; // 这是初始化!调用拷贝构造函数
obj2.display();
// 情况2: 带参数的初始化
std::cout << "\n2. 带参数的初始化:" << std::endl;
MyClass obj3 = MyClass(20, "Temporary"); // 初始化,可能被优化
obj3.display();
// 情况3: 列表初始化(C++11)
std::cout << "\n3. 列表初始化:" << std::endl;
MyClass obj4 = {30, "FromList"}; // 初始化
obj4.display();
std::cout << "\n=== 等于号作为赋值 ===" << std::endl;
// 情况4: 已存在对象的等于号是赋值
std::cout << "\n4. 对象赋值:" << std::endl;
MyClass obj5(40, "FirstValue");
MyClass obj6(50, "SecondValue");
obj5 = obj6; // 这是赋值!调用拷贝赋值运算符
obj5.display();
return 0;
}
封闭类和派生类的初始化
如果对内部类和基类自定义了构造函数













注意事项
1.性能差异:初始化通常比"先默认构造再赋值"更高效
2.const成员和引用成员:必须在初始化列表中初始化,不能在构造函数体中赋值
3.explicit构造函数:影响等于号初始化的行为
class ExplicitExample {
int x;
public:
explicit ExplicitExample(int val) : x(val) {}
};
void explicitExample() {
// ExplicitExample obj = 10; // 错误:explicit构造函数不能用于拷贝初始化
ExplicitExample obj(10); // 正确:直接初始化
ExplicitExample obj2 = ExplicitExample(10); // 正确:显式构造
}
优先使用初始化而不是先构造后赋值
对于类类型成员,使用成员初始化列表
注意区分声明时的等于号(初始化)和语句中的等于号(赋值)
更多推荐


所有评论(0)