一、构造函数基础
1.1 构造函数概述与类型
class ConstructorBasics {
private:
int* data;
size_t size;
std::string name;
const int id; // const成员
int& ref; // 引用成员
static int counter; // 静态成员
public:
// 1. 默认构造函数
ConstructorBasics(int& r)
: data(nullptr)
, size(0)
, name("default")
, id(++counter) // const成员必须在初始化列表中初始化
, ref(r) // 引用成员必须在初始化列表中初始化
{
std::cout << "Default constructor called, id: " << id << "\n";
}
// 2. 参数化构造函数
ConstructorBasics(size_t s, const std::string& n, int& r)
: data(new int[s]()) // 值初始化
, size(s)
, name(n)
, id(++counter)
, ref(r) {
std::cout << "Parameterized constructor called, id: " << id << "\n";
}
// 3. 拷贝构造函数
ConstructorBasics(const ConstructorBasics& other)
: size(other.size)
, name(other.name)
, id(++counter)
, ref(other.ref) {
data = new int[size];
std::copy(other.data, other.data + size, data);
std::cout << "Copy constructor called, id: " << id << "\n";
}
// 4. 移动构造函数 (C++11)
ConstructorBasics(ConstructorBasics&& other) noexcept
: data(std::exchange(other.data, nullptr))
, size(std::exchange(other.size, 0))
, name(std::move(other.name))
, id(++counter)
, ref(other.ref) {
std::cout << "Move constructor called, id: " << id << "\n";
}
// 5. 委托构造函数 (C++11)
ConstructorBasics(const std::string& n, int& r)
: ConstructorBasics(10, n, r) { // 委托给另一个构造函数
std::cout << "Delegating constructor called\n";
}
// 6. 转换构造函数(单参数构造函数)
explicit ConstructorBasics(int value, int& r) // explicit防止隐式转换
: ConstructorBasics(1, "single", r) {
if (data) data[0] = value;
}
// 析构函数
~ConstructorBasics() {
delete[] data;
std::cout << "Destructor called, id: " << id << "\n";
}
};
int ConstructorBasics::counter = 0;
1.2 初始化列表详解
class InitializationList {
private:
// 初始化顺序:按声明顺序,不是初始化列表顺序
int a;
int b;
int c;
// 不同类型成员的初始化
const int constMember;
int& refMember;
int normalMember;
static int staticMember; // 不在初始化列表中初始化
// 对象成员
std::string strMember;
std::vector<int> vecMember;
// 数组成员
int arrayMember[5];
public:
// 初始化列表的正确使用
InitializationList(int x, int& ref)
: b(x) // 警告:初始化顺序与声明顺序不符
, a(b + 1) // 危险:b还未初始化(按声明顺序a先于b)
, c(a + b) //
, constMember(100) // const成员必须在这里初始化
, refMember(ref) // 引用成员必须在这里初始化
, normalMember(200) // 普通成员建议在这里初始化
, strMember("hello") // 调用string的构造函数
, vecMember{1,2,3,4,5} // 列表初始化
, arrayMember{10,20,30,40,50} // C++11数组初始化
{
// 构造函数体:此时所有成员已经初始化
// staticMember = 300; // 静态成员通过其他方式初始化
}
// 使用默认成员初始化器 (C++11)
class ModernInit {
int x = 10; // 默认值
double y{3.14}; // 统一初始化
std::string s{"default"}; //
std::vector<int> v{1,2,3}; //
int* ptr = nullptr; //
public:
ModernInit() = default; // 使用默认值
ModernInit(int val) : x(val) {} // 覆盖x的默认值,其他使用默认值
};
};
// 静态成员初始化
int InitializationList::staticMember = 500;
1.3 拷贝构造函数深入
class CopyConstructor {
private:
int* data;
size_t size;
std::shared_ptr<int> sharedData;
public:
// 深拷贝实现
CopyConstructor(const CopyConstructor& other)
: size(other.size)
, sharedData(other.sharedData) { // 共享所有权
// 深拷贝动态内存
if (other.data) {
data = new int[size];
std::copy(other.data, other.data + size, data);
} else {
data = nullptr;
}
}
// 拷贝构造函数的调用场景
static void demonstrateCopyScenarios() {
CopyConstructor obj1(10);
// 场景1:直接初始化
CopyConstructor obj2(obj1);
// 场景2:拷贝初始化
CopyConstructor obj3 = obj1;
// 场景3:函数参数传值
void processObject(CopyConstructor obj);
processObject(obj1);
// 场景4:函数返回值(可能被优化)
auto getObject = []() {
CopyConstructor temp(5);
return temp; // 可能触发拷贝或移动
};
CopyConstructor obj4 = getObject();
// 场景5:容器操作
std::vector<CopyConstructor> vec;
vec.push_back(obj1); // 拷贝构造
}
// 禁用拷贝构造
class NoCopy {
NoCopy(const NoCopy&) = delete; // C++11方式
// 或者声明为private(C++98方式)
};
};
1.4 移动构造函数详解
class MoveConstructor {
private:
int* data;
size_t size;
std::string name;
public:
// 移动构造函数实现
MoveConstructor(MoveConstructor&& other) noexcept
: data(std::exchange(other.data, nullptr)) // 转移所有权
, size(std::exchange(other.size, 0))
, name(std::move(other.name)) {
std::cout << "Move constructor called\n";
}
// 移动构造的场景
static void demonstrateMoveScenarios() {
// 场景1:显式移动
MoveConstructor obj1(100);
MoveConstructor obj2(std::move(obj1)); // obj1变为"移后"状态
// 场景2:返回局部对象(NRVO可能优化)
auto createObject = []() {
MoveConstructor temp(200);
return temp; // 返回值优化或移动构造
};
MoveConstructor obj3 = createObject();
// 场景3:临时对象
MoveConstructor obj4(MoveConstructor(300)); // 移动构造
// 场景4:容器操作
std::vector<MoveConstructor> vec;
vec.push_back(MoveConstructor(400)); // 移动构造
MoveConstructor obj5(500);
vec.emplace_back(std::move(obj5)); // 移动构造
}
// 完美转发构造函数
template<typename... Args>
MoveConstructor(Args&&... args) {
// 完美转发参数
construct(std::forward<Args>(args)...);
}
private:
template<typename... Args>
void construct(Args&&... args) {
// 实际构造逻辑
}
};
二、特殊构造函数
2.1 explicit关键字的使用
class ExplicitDemo {
private:
int value;
public:
// 隐式转换构造函数(不推荐)
ExplicitDemo(int v) : value(v) {}
// explicit构造函数(推荐)
class Safe {
int value;
public:
explicit Safe(int v) : value(v) {}
// explicit转换运算符 (C++11)
explicit operator bool() const {
return value != 0;
}
explicit operator int() const {
return value;
}
};
static void demonstrateExplicit() {
// 隐式转换(不安全)
ExplicitDemo obj1 = 42; // 允许
ExplicitDemo obj2(42); // 允许
void process(ExplicitDemo obj);
process(42); // 允许(隐式转换)
// explicit构造函数(安全)
// Safe safe1 = 42; // 错误:不允许隐式转换
Safe safe2(42); // 正确:显式构造
Safe safe3{42}; // 正确:直接初始化
// explicit转换
if (safe2) {} // 错误:需要显式转换
if (static_cast<bool>(safe2)) {} // 正确
// 但在条件语句中可以(特殊规则)
if (safe2) {} // C++11后允许
while (safe2) {} // C++11后允许
}
};
2.2 初始化列表构造函数
class InitListConstructor {
private:
std::vector<int> data;
public:
// 普通构造函数
InitListConstructor(int size) : data(size) {
std::cout << "Size constructor: " << size << "\n";
}
// 初始化列表构造函数
InitListConstructor(std::initializer_list<int> init)
: data(init) {
std::cout << "Initializer list constructor\n";
}
// 可变参数模板构造函数
template<typename... Args>
InitListConstructor(Args... args)
: data{args...} {
std::cout << "Variadic template constructor\n";
}
static void demonstrateUsage() {
InitListConstructor obj1(5); // 调用size构造函数
InitListConstructor obj2{5}; // 调用初始化列表构造函数
InitListConstructor obj3{1,2,3,4}; // 初始化列表构造函数
InitListConstructor obj4 = {1,2,3}; // 初始化列表构造函数
// 注意优先级
std::vector<int> v1(5); // 5个元素,值为0
std::vector<int> v2{5}; // 1个元素,值为5
std::vector<int> v3(5, 2); // 5个元素,值为2
std::vector<int> v4{5, 2}; // 2个元素,值为5和2
}
};
2.3 constexpr构造函数
class ConstexprConstructor {
private:
int value;
double ratio;
public:
// constexpr构造函数 (C++11)
constexpr ConstexprConstructor(int v, double r)
: value(v), ratio(r) {
// C++11: 函数体必须为空
// C++14: 可以有简单语句
}
// C++14 constexpr构造函数
constexpr ConstexprConstructor(int v)
: value(v), ratio(1.0) {
if (v < 0) {
value = -v; // C++14允许
}
}
constexpr int getValue() const { return value; }
constexpr double getRatio() const { return ratio; }
// 编译时对象创建
static constexpr ConstexprConstructor compile_time_obj{42, 3.14};
};
// 编译时使用
constexpr ConstexprConstructor global_obj(100, 2.5);
constexpr int val = global_obj.getValue(); // 编译时计算
三、析构函数详解
3.1 析构函数基础
class DestructorBasics {
private:
int* data;
std::FILE* file;
std::thread* worker;
public:
DestructorBasics()
: data(new int[100])
, file(std::fopen("data.txt", "w"))
, worker(new std::thread([]{ /* work */ })) {
}
// 析构函数
~DestructorBasics() {
// 清理顺序很重要
// 1. 停止线程
if (worker) {
if (worker->joinable()) {
worker->join();
}
delete worker;
}
// 2. 关闭文件
if (file) {
std::fclose(file);
}
// 3. 释放内存
delete[] data;
std::cout << "Destructor called\n";
}
// 析构函数调用时机
static void demonstrateDestruction() {
// 1. 自动对象离开作用域
{
DestructorBasics obj;
} // 这里调用析构函数
// 2. delete删除动态对象
DestructorBasics* ptr = new DestructorBasics();
delete ptr; // 调用析构函数
// 3. 对象数组
DestructorBasics* arr = new DestructorBasics[3];
delete[] arr; // 调用每个元素的析构函数
// 4. 容器销毁
{
std::vector<DestructorBasics> vec(2);
} // vector销毁时调用每个元素的析构函数
// 5. 程序结束时的全局/静态对象
static DestructorBasics static_obj; // main结束后析构
}
};
3.2 虚析构函数
class VirtualDestructor {
// 基类必须有虚析构函数
class Base {
protected:
int* baseData;
public:
Base() : baseData(new int[10]) {
std::cout << "Base constructor\n";
}
// 虚析构函数(重要!)
virtual ~Base() {
delete[] baseData;
std::cout << "Base destructor\n";
}
virtual void process() = 0;
};
class Derived : public Base {
private:
double* derivedData;
public:
Derived() : derivedData(new double[20]) {
std::cout << "Derived constructor\n";
}
~Derived() override { // C++11 override确保正确重写
delete[] derivedData;
std::cout << "Derived destructor\n";
}
void process() override {
// 实现
}
};
static void demonstrateVirtualDestructor() {
// 正确:有虚析构函数
Base* ptr1 = new Derived();
delete ptr1; // 正确调用Derived和Base的析构函数
// 如果Base没有虚析构函数
// delete ptr1; // 只调用Base析构函数,内存泄漏!
// 使用智能指针自动管理
std::unique_ptr<Base> ptr2 = std::make_unique<Derived>();
// 自动正确析构
}
// 纯虚析构函数
class AbstractBase {
public:
virtual ~AbstractBase() = 0; // 纯虚析构函数
};
// 纯虚析构函数必须提供实现
AbstractBase::~AbstractBase() {
// 清理基类资源
}
};
3.3 析构函数异常处理
class DestructorException {
private:
std::vector<std::string> resources;
public:
// 析构函数不应该抛出异常
~DestructorException() noexcept { // C++11默认noexcept
try {
// 可能抛出异常的操作
for (auto& res : resources) {
riskyCleanup(res);
}
} catch (const std::exception& e) {
// 记录错误但不传播异常
std::cerr << "Error in destructor: " << e.what() << "\n";
// std::terminate(); // 或者终止程序
} catch (...) {
// 捕获所有异常
std::cerr << "Unknown error in destructor\n";
}
}
private:
void riskyCleanup(const std::string& resource) {
// 可能抛出异常的清理操作
if (resource.empty()) {
throw std::runtime_error("Invalid resource");
}
}
// 两阶段析构模式
class TwoPhaseDestruction {
private:
bool cleaned = false;
public:
// 显式清理方法(可以抛出异常)
void cleanup() {
if (!cleaned) {
// 执行可能失败的清理
riskyOperation();
cleaned = true;
}
}
// 析构函数(不抛出异常)
~TwoPhaseDestruction() noexcept {
if (!cleaned) {
try {
cleanup();
} catch (...) {
// 忽略异常
}
}
}
private:
void riskyOperation() {
// 可能抛出异常
}
};
};
四、构造与析构顺序
4.1 对象构造顺序
class ConstructionOrder {
// 成员构造顺序
class MemberOrder {
class A {
public:
A(int n) { std::cout << "A(" << n << ") "; }
};
class B {
public:
B(int n) { std::cout << "B(" << n << ") "; }
};
// 成员按声明顺序构造,不是初始化列表顺序
A a1;
B b1;
A a2;
B b2;
public:
MemberOrder()
: b2(4) // 警告:初始化顺序与声明顺序不符
, a1(1)
, b1(2)
, a2(3) {
std::cout << "MemberOrder() ";
}
// 输出: A(1) B(2) A(3) B(4) MemberOrder()
};
// 继承中的构造顺序
class Base {
public:
Base() { std::cout << "Base() "; }
Base(int) { std::cout << "Base(int) "; }
};
class Member {
public:
Member() { std::cout << "Member() "; }
};
class Derived : public Base {
Member m;
public:
Derived() : Base(1), m() {
std::cout << "Derived() ";
}
// 输出: Base(int) Member() Derived()
};
// 多重继承的构造顺序
class Base1 {
public:
Base1() { std::cout << "Base1() "; }
};
class Base2 {
public:
Base2() { std::cout << "Base2() "; }
};
class MultiDerived : public Base1, public Base2 {
public:
MultiDerived() {
std::cout << "MultiDerived() ";
}
// 输出: Base1() Base2() MultiDerived()
// 顺序由继承列表决定,不是初始化列表
};
// 虚继承的构造顺序
class VBase {
public:
VBase(int n) { std::cout << "VBase(" << n << ") "; }
};
class VDerived1 : virtual public VBase {
public:
VDerived1() : VBase(1) { std::cout << "VDerived1() "; }
};
class VDerived2 : virtual public VBase {
public:
VDerived2() : VBase(2) { std::cout << "VDerived2() "; }
};
class Final : public VDerived1, public VDerived2 {
public:
Final() : VBase(3) { // 最终派生类负责构造虚基类
std::cout << "Final() ";
}
// 输出: VBase(3) VDerived1() VDerived2() Final()
};
};
4.2 析构顺序
class DestructionOrder {
// 析构顺序与构造顺序相反
class Example {
class Resource {
std::string name;
public:
Resource(const std::string& n) : name(n) {
std::cout << "Construct " << name << "\n";
}
~Resource() {
std::cout << "Destruct " << name << "\n";
}
};
Resource r1{"r1"};
Resource r2{"r2"};
Resource r3{"r3"};
public:
Example() {
std::cout << "Example constructed\n";
}
~Example() {
std::cout << "Example destructor begins\n";
// 成员析构顺序:r3, r2, r1(声明的逆序)
}
};
// 局部对象析构顺序
static void localObjectDestruction() {
class Object {
int id;
public:
Object(int i) : id(i) {
std::cout << "Construct " << id << "\n";
}
~Object() {
std::cout << "Destruct " << id << "\n";
}
};
Object obj1(1);
{
Object obj2(2);
Object obj3(3);
} // obj3析构,然后obj2析构
Object obj4(4);
} // obj4析构,然后obj1析构
// 异常时的析构
static void exceptionDestruction() {
class RAII {
std::string name;
public:
RAII(const std::string& n) : name(n) {
std::cout << "Acquire " << name << "\n";
}
~RAII() {
std::cout << "Release " << name << "\n";
}
};
try {
RAII r1("resource1");
RAII r2("resource2");
throw std::runtime_error("error");
RAII r3("resource3"); // 不会构造
} catch (...) {
// r2和r1按构造的逆序析构
std::cout << "Exception caught\n";
}
}
};
五、特殊情况和最佳实践
5.1 Rule of Five/Three/Zero
class RuleOfFive {
// Rule of Five: 如果定义了其中一个,通常需要定义所有五个
class Complete {
private:
int* data;
size_t size;
public:
// 1. 构造函数
explicit Complete(size_t s)
: data(new int[s]()), size(s) {}
// 2. 析构函数
~Complete() {
delete[] data;
}
// 3. 拷贝构造函数
Complete(const Complete& other)
: data(new int[other.size])
, size(other.size) {
std::copy(other.data, other.data + size, data);
}
// 4. 拷贝赋值运算符
Complete& operator=(const Complete& other) {
if (this != &other) {
Complete temp(other);
swap(temp);
}
return *this;
}
// 5. 移动构造函数
Complete(Complete&& other) noexcept
: data(std::exchange(other.data, nullptr))
, size(std::exchange(other.size, 0)) {}
// 6. 移动赋值运算符
Complete& operator=(Complete&& other) noexcept {
if (this != &other) {
delete[] data;
data = std::exchange(other.data, nullptr);
size = std::exchange(other.size, 0);
}
return *this;
}
private:
void swap(Complete& other) noexcept {
std::swap(data, other.data);
std::swap(size, other.size);
}
};
// Rule of Zero: 使用RAII包装器,让编译器生成特殊成员函数
class RuleOfZero {
private:
std::unique_ptr<int[]> data;
std::vector<int> vec;
std::string name;
public:
explicit RuleOfZero(size_t s)
: data(std::make_unique<int[]>(s))
, vec(s)
, name("default") {
// 不需要定义特殊成员函数
// 编译器生成的版本就是正确的
}
// 使用 = default 显式要求编译器生成
RuleOfZero(const RuleOfZero&) = default;
RuleOfZero& operator=(const RuleOfZero&) = default;
RuleOfZero(RuleOfZero&&) = default;
RuleOfZero& operator=(RuleOfZero&&) = default;
~RuleOfZero() = default;
};
};
5.2 RAII和异常安全
class RAIIPattern {
// RAII资源管理
template<typename Resource, typename Deleter>
class RAIIWrapper {
private:
Resource* resource;
Deleter deleter;
public:
explicit RAIIWrapper(Resource* r, Deleter d = Deleter{})
: resource(r), deleter(d) {
if (!resource) {
throw std::invalid_argument("Null resource");
}
}
~RAIIWrapper() {
if (resource) {
deleter(resource);
}
}
// 删除拷贝操作
RAIIWrapper(const RAIIWrapper&) = delete;
RAIIWrapper& operator=(const RAIIWrapper&) = delete;
// 移动操作
RAIIWrapper(RAIIWrapper&& other) noexcept
: resource(std::exchange(other.resource, nullptr))
, deleter(std::move(other.deleter)) {}
RAIIWrapper& operator=(RAIIWrapper&& other) noexcept {
if (this != &other) {
if (resource) {
deleter(resource);
}
resource = std::exchange(other.resource, nullptr);
deleter = std::move(other.deleter);
}
return *this;
}
Resource* get() { return resource; }
Resource* operator->() { return resource; }
Resource& operator*() { return *resource; }
};
// 使用示例
static void useRAII() {
// 文件资源管理
auto fileDeleter = [](FILE* f) {
if (f) std::fclose(f);
};
RAIIWrapper<FILE, decltype(fileDeleter)>
file(std::fopen("data.txt", "r"), fileDeleter);
// 内存资源管理
auto arrayDeleter = [](int* p) { delete[] p; };
RAIIWrapper<int, decltype(arrayDeleter)>
array(new int[100], arrayDeleter);
// 互斥锁管理
std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx); // RAII锁管理
}
};
5.3 构造函数的异常处理
class ConstructorExceptions {
class SafeConstruction {
private:
std::unique_ptr<int[]> data1;
std::unique_ptr<double[]> data2;
std::vector<std::string> names;
public:
SafeConstruction(size_t size)
try : data1(std::make_unique<int[]>(size))
, data2(std::make_unique<double[]>(size))
, names(size) {
// 构造函数体
if (size == 0) {
throw std::invalid_argument("Size cannot be zero");
}
// 初始化数据
for (size_t i = 0; i < size; ++i) {
data1[i] = i;
data2[i] = i * 2.0;
names[i] = "Item_" + std::to_string(i);
}
} catch (const std::bad_alloc& e) {
// 处理内存分配失败
std::cerr << "Memory allocation failed: " << e.what() << "\n";
throw; // 重新抛出
} catch (const std::exception& e) {
// 处理其他异常
std::cerr << "Construction failed: " << e.what() << "\n";
throw;
}
// 函数try块(处理成员初始化异常)
SafeConstruction(const SafeConstruction& other)
try : data1(std::make_unique<int[]>(other.size()))
, data2(std::make_unique<double[]>(other.size()))
, names(other.names) {
// 拷贝数据
} catch (...) {
// 处理成员初始化异常
// 注意:这里不能访问成员变量
std::cerr << "Copy construction failed\n";
throw; // 必须重新抛出
}
private:
size_t size() const { return names.size(); }
};
};
5.4 全局和静态对象的构造/析构
class GlobalStaticObjects {
// 静态局部变量(Meyer's Singleton)
class Singleton {
private:
Singleton() {
std::cout << "Singleton constructed\n";
}
public:
static Singleton& getInstance() {
static Singleton instance; // 第一次调用时构造
return instance; // 程序结束时析构
}
~Singleton() {
std::cout << "Singleton destroyed\n";
}
// 删除拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
// 全局对象初始化顺序问题
class GlobalInit {
private:
static int& getCounter() {
static int counter = 0; // 避免全局初始化顺序问题
return counter;
}
public:
GlobalInit() {
++getCounter();
std::cout << "Global object " << getCounter()
<< " constructed\n";
}
~GlobalInit() {
std::cout << "Global object " << getCounter()
<< " destroyed\n";
--getCounter();
}
};
// 使用std::call_once确保单次初始化
class OnceInit {
private:
static std::once_flag initFlag;
static std::unique_ptr<OnceInit> instance;
OnceInit() {
std::cout << "OnceInit constructed\n";
}
public:
static OnceInit& getInstance() {
std::call_once(initFlag, []() {
instance.reset(new OnceInit());
});
return *instance;
}
};
};
// 静态成员定义
std::once_flag GlobalStaticObjects::OnceInit::initFlag;
std::unique_ptr<GlobalStaticObjects::OnceInit>
GlobalStaticObjects::OnceInit::instance;
六、性能优化
6.1 构造函数优化
class ConstructorOptimization {
// 避免不必要的默认构造
class Efficient {
private:
std::vector<int> data;
std::string name;
public:
// 使用成员初始化列表,避免默认构造后赋值
Efficient(size_t size, const std::string& n)
: data(size, 0) // 直接构造指定大小
, name(n) { // 直接构造,避免默认构造+赋值
// 不要这样做:
// data = std::vector<int>(size, 0); // 默认构造+赋值
// name = n; // 默认构造+赋值
}
// 使用reserve优化vector
Efficient(const std::vector<int>& values)
: name("from_vector") {
data.reserve(values.size()); // 预分配空间
for (int val : values) {
data.push_back(val * 2);
}
}
// 完美转发减少拷贝
template<typename T>
void addElement(T&& element) {
data.push_back(std::forward<T>(element));
}
// 使用emplace构造
template<typename... Args>
void emplaceElement(Args&&... args) {
data.emplace_back(std::forward<Args>(args)...);
}
};
// RVO/NRVO优化
class ReturnOptimization {
public:
static ReturnOptimization createObject() {
ReturnOptimization obj;
// 设置obj...
return obj; // NRVO优化,避免拷贝
}
static ReturnOptimization createConditional(bool flag) {
if (flag) {
return ReturnOptimization("option1");
} else {
return ReturnOptimization("option2");
}
// RVO优化
}
private:
std::string data;
explicit ReturnOptimization(const std::string& s = "")
: data(s) {}
};
};