C++ 中的构造函数类型
-
默认构造函数:
- 没有参数,用于创建默认初始化的对象。
- 如果没有显式定义,编译器会自动生成一个默认构造函数。
class MyClass { public: MyClass() {} // 默认构造函数 };
-
参数化构造函数:
- 接受一个或多个参数,用于创建以特定值初始化的对象。
class MyClass { public: MyClass(int value) : _value(value) {} // 参数化构造函数 private: int _value; };
-
拷贝构造函数:
- 接受一个同类型的对象作为参数,用于创建该对象的副本。
class MyClass { public: MyClass(const MyClass& other) : _value(other._value) {} // 拷贝构造函数 private: int _value; };
-
移动构造函数:
- 接受一个右值引用作为参数,用于将资源从一个对象转移到另一个对象。
class MyClass { public: MyClass(MyClass&& other) : _value(std::move(other._value)) {} // 移动构造函数 private: int _value; };
-
转换构造函数:
- 接受一个不同类型的值作为参数,用于将该值转换为当前类型。
class MyClass { public: MyClass(int value) : _value(value) {} // 转换构造函数 private: int _value; };
右值引用构造函数的好处:
-
避免不必要的拷贝: 对于临时对象或即将被销毁的对象,使用右值引用构造函数可以避免不必要的拷贝操作,提高效率。
-
资源转移: 右值引用构造函数允许将资源从一个对象转移到另一个对象,而不是进行拷贝,这对于管理动态分配的内存和其他资源非常有用。
举例说明:
#include <iostream>
#include <string>
class MyClass {
public:
MyClass(const std::string& str) : _str(str) {
std::cout << "拷贝构造函数被调用\n";
}
MyClass(std::string&& str) : _str(std::move(str)) {
std::cout << "移动构造函数被调用\n";
}
std::string getStr() const {
return _str;
}
private:
std::string _str;
};
int main() {
// 使用拷贝构造函数
MyClass obj1("Hello");
MyClass obj2(obj1);
std::cout << "obj2.getStr(): " << obj2.getStr() << std::endl;
// 使用移动构造函数
MyClass obj3(std::move(obj1));
std::cout << "obj3.getStr(): " << obj3.getStr() << std::endl;
std::cout << "obj1.getStr(): " << obj1.getStr() << std::endl; // obj1 的 _str 被移动到 obj3,这里应该为空
return 0;
}
输出:
拷贝构造函数被调用
obj2.getStr(): Hello
移动构造函数被调用
obj3.getStr(): Hello
obj1.getStr():
在这个例子中,obj2
使用拷贝构造函数创建了 obj1
的副本,而 obj3
使用移动构造函数将 obj1
的资源转移到了自己。由于移动构造函数将资源转移,obj1
的 _str
属性被清空。
构造函数的主要修饰语法
1. 访问修饰符:
- public: 公共构造函数,可以在任何地方被访问。
- private: 私有构造函数,只能在类内部或友元函数中被访问,限制了对象的创建。
- protected: 受保护的构造函数,只能在类内部、子类和友元函数中被访问。
class MyClass {
public:
MyClass() {} // 公共构造函数
private:
MyClass(int value) {} // 私有构造函数
protected:
MyClass(const MyClass& other) {} // 受保护的构造函数
};
2. 关键字 explicit
:
- 用于阻止构造函数进行隐式转换。
class MyClass {
public:
explicit MyClass(int value) {} // 阻止将int隐式转换为MyClass
};
int main() {
MyClass obj1(10); // 正确,显式调用构造函数
MyClass obj2 = 10; // 错误,无法隐式转换
return 0;
}
3. constexpr
修饰符:
- 用于创建常量表达式构造函数,它必须在编译时计算出结果。
class MyClass {
public:
constexpr MyClass(int value) : _value(value) {} // 常量表达式构造函数
private:
int _value;
};
int main() {
constexpr MyClass obj(10); // 在编译时初始化
return 0;
}
4. delete
修饰符:
- 用于禁用默认构造函数。
class MyClass {
public:
MyClass(int value) {}
private:
MyClass() = delete; // 禁用默认构造函数
};
5. = default
:
- 用于显式地调用默认构造函数。
class MyClass {
public:
MyClass() = default; // 显式地调用默认构造函数
};
6. = delete
:
- 用于显式地禁止默认构造函数。
class MyClass {
public:
MyClass() = delete; // 禁止默认构造函数
};
注意:
- 访问修饰符决定了构造函数的访问权限。
explicit
阻止隐式类型转换,但不会阻止显式转换。constexpr
用于创建常量表达式构造函数,它必须在编译时计算出结果。delete
禁用默认构造函数,阻止编译器自动生成默认构造函数。= default
和= delete
用于显式地指定默认构造函数的行为。
希望这些信息能帮助你理解构造函数修饰语法。