C++ Primer 第18章:用于大型程序的工具

C++ Primer 第18章:用于大型程序的工具


18.1 异常处理

18.1.1 抛出异常

复制代码
// throw_exceptions.cpp -- 抛出异常
#include <iostream>
#include <stdexcept>
#include <string>
​
// 异常对象在 throw 时被拷贝
// 异常对象的类型决定哪个 catch 子句被选中
​
class MyException : public std::runtime_error
{
public:
    MyException(const std::string& msg, int code)
        : std::runtime_error(msg), errorCode_(code) {}
​
    int code() const { return errorCode_; }
​
private:
    int errorCode_;
};
​
void level3()
{
    // throw 表达式:创建异常对象并抛出
    throw MyException("level3发生错误", 404);
}
​
void level2()
{
    try
    {
        level3();
    }
    catch (MyException& e)
    {
        std::cout << "level2捕获并重新抛出:" << e.what() << std::endl;
        throw;   // 重新抛出当前异常(保持原始类型)
        // throw e;   // ⚠️ 这会切割异常对象!
    }
}
​
int main()
{
    using namespace std;
​
    // ===== 基本异常处理 =====
    try
    {
        level2();
    }
    catch (const MyException& e)
    {
        cout << "main捕获:" << e.what()
             << " 错误码:" << e.code() << endl;
    }
    catch (const runtime_error& e)
    {
        cout << "runtime_error:" << e.what() << endl;
    }
    catch (const exception& e)
    {
        cout << "exception:" << e.what() << endl;
    }
    catch (...)
    {
        cout << "未知异常" << endl;
    }
​
    // ===== 异常与析构函数 =====
    // 析构函数不应该抛出异常!
    // 如果析构函数抛出异常,且此时已有异常在传播,程序会调用 terminate()
​
    return 0;
}

18.1.2 栈展开与异常安全

复制代码
// stack_unwinding.cpp -- 栈展开
#include <iostream>
#include <memory>
#include <string>
​
class Resource
{
public:
    Resource(const std::string& name) : name_(name)
    {
        std::cout << "[获取] " << name_ << std::endl;
    }
    ~Resource()
    {
        std::cout << "[释放] " << name_ << std::endl;
    }
​
private:
    std::string name_;
};
​
// ===== 异常安全的三个级别 =====
// 1. 基本保证:异常后对象处于有效状态(可能改变)
// 2. 强保证:异常后对象状态不变(事务性)
// 3. 不抛出保证:操作不会抛出异常(noexcept)
​
class SafeVector
{
private:
    std::vector<int> data_;
​
public:
    // 强保证:使用拷贝并交换
    void push_back_safe(int val)
    {
        auto temp = data_;   // 拷贝
        temp.push_back(val); // 可能抛出
        data_.swap(temp);    // noexcept,不会失败
    }
​
    // 基本保证:可能部分完成
    void push_back_basic(int val)
    {
        data_.push_back(val);   // 可能抛出
    }
};
​
void demonstrateUnwinding()
{
    Resource r1("资源A");
    {
        Resource r2("资源B");
        throw std::runtime_error("测试异常");
        // r2 在这里自动析构(栈展开)
    }
    // r1 在这里自动析构(栈展开)
}
​
int main()
{
    using namespace std;
​
    cout << "===== 栈展开演示 =====" << endl;
    try
    {
        demonstrateUnwinding();
    }
    catch (const exception& e)
    {
        cout << "捕获:" << e.what() << endl;
    }
​
    // ===== RAII 保证异常安全 =====
    cout << "\n===== RAII 异常安全 =====" << endl;
    try
    {
        auto p1 = make_unique<Resource>("智能指针资源1");
        auto p2 = make_unique<Resource>("智能指针资源2");
        throw runtime_error("RAII测试");
        // p1, p2 自动释放,无内存泄漏
    }
    catch (const exception& e)
    {
        cout << "捕获:" << e.what() << endl;
    }
​
    return 0;
}

18.1.3 noexcept 异常说明

复制代码
// noexcept_demo.cpp -- noexcept
#include <iostream>
#include <vector>
#include <stdexcept>
​
// noexcept:承诺函数不抛出异常
// 如果抛出,程序调用 std::terminate()
​
// 析构函数默认是 noexcept
class MyClass
{
public:
    ~MyClass() noexcept   // 析构函数应该是 noexcept
    {
        // 不应该在析构函数中抛出异常
    }
​
    // 移动操作应该是 noexcept(让容器使用移动而非拷贝)
    MyClass(MyClass&&) noexcept = default;
    MyClass& operator=(MyClass&&) noexcept = default;
};
​
// noexcept 说明符
void safeFunc() noexcept
{
    // 不会抛出异常
}
​
// noexcept 运算符:检查表达式是否会抛出
template <typename T>
void swap(T& a, T& b) noexcept(noexcept(T(std::move(a))))
{
    T temp = std::move(a);
    a = std::move(b);
    b = std::move(temp);
}
​
int main()
{
    using namespace std;
​
    // 检查函数是否 noexcept
    cout << boolalpha;
    cout << "safeFunc是否noexcept:" << noexcept(safeFunc()) << endl;
​
    // vector 在扩容时:
    // 如果移动构造是 noexcept,使用移动(高效)
    // 否则使用拷贝(安全但低效)
    vector<MyClass> v;
    v.push_back(MyClass{});   // 使用移动(因为移动构造是noexcept)
​
    return 0;
}

18.1.4 异常类层次结构

复制代码
// exception_hierarchy.cpp -- 异常类层次
#include <iostream>
#include <stdexcept>
#include <string>
​
/*
std::exception
├── std::bad_alloc          new 失败
├── std::bad_cast           dynamic_cast 失败
├── std::bad_typeid         typeid 失败
├── std::bad_exception
└── std::logic_error        逻辑错误(可预防)
    ├── std::domain_error   定义域错误
    ├── std::invalid_argument 无效参数
    ├── std::length_error   长度错误
    └── std::out_of_range   越界
└── std::runtime_error      运行时错误(难以预防)
    ├── std::overflow_error  上溢
    ├── std::underflow_error 下溢
    └── std::range_error     范围错误
*/
​
// 自定义异常层次
class AppException : public std::exception
{
protected:
    std::string message_;
    int         code_;
​
public:
    AppException(const std::string& msg, int code)
        : message_(msg), code_(code) {}
​
    const char* what() const noexcept override
    {
        return message_.c_str();
    }
​
    int code() const { return code_; }
};
​
class DatabaseException : public AppException
{
public:
    DatabaseException(const std::string& msg)
        : AppException("数据库错误: " + msg, 1001) {}
};
​
class NetworkException : public AppException
{
public:
    NetworkException(const std::string& msg)
        : AppException("网络错误: " + msg, 2001) {}
};
​
class ValidationException : public AppException
{
private:
    std::string field_;
​
public:
    ValidationException(const std::string& field, const std::string& msg)
        : AppException("验证错误[" + field + "]: " + msg, 3001),
          field_(field) {}
​
    const std::string& field() const { return field_; }
};
​
void processRequest(int type)
{
    switch (type)
    {
        case 1: throw DatabaseException("连接超时");
        case 2: throw NetworkException("DNS解析失败");
        case 3: throw ValidationException("email", "格式无效");
        default: throw AppException("未知错误", 9999);
    }
}
​
int main()
{
    using namespace std;
​
    for (int i = 1; i <= 4; i++)
    {
        try
        {
            processRequest(i);
        }
        catch (const ValidationException& e)
        {
            cout << "[验证] " << e.what()
                 << " 字段:" << e.field() << endl;
        }
        catch (const DatabaseException& e)
        {
            cout << "[数据库] " << e.what()
                 << " 代码:" << e.code() << endl;
        }
        catch (const NetworkException& e)
        {
            cout << "[网络] " << e.what() << endl;
        }
        catch (const AppException& e)
        {
            cout << "[应用] " << e.what()
                 << " 代码:" << e.code() << endl;
        }
    }
​
    return 0;
}

18.2 命名空间

18.2.1 命名空间基础

复制代码
// namespace_basics.cpp -- 命名空间基础
#include <iostream>
#include <string>
​
// ===== 定义命名空间 =====
namespace cplusplus_primer
{
    class Sales_data { /* ... */ };
    Sales_data operator+(const Sales_data&, const Sales_data&);
​
    class Query { /* ... */ };
    class Query_base { /* ... */ };
}
​
// ===== 命名空间可以不连续(开放性)=====
namespace cplusplus_primer
{
    // 继续添加成员
    class QueryResult { /* ... */ };
}
​
// ===== 嵌套命名空间 =====
namespace outer
{
    int x = 1;
​
    namespace inner
    {
        int x = 2;   // 与 outer::x 不冲突
​
        void show()
        {
            std::cout << "inner::x = " << x << std::endl;
            std::cout << "outer::x = " << outer::x << std::endl;
        }
    }
}
​
// ===== 内联命名空间(C++11)=====
// 内联命名空间的成员可以直接被外层命名空间访问
namespace FifthEd
{
    inline namespace FifthEdV1
    {
        void func() { std::cout << "FifthEdV1::func" << std::endl; }
    }
​
    namespace FifthEdV2
    {
        void func() { std::cout << "FifthEdV2::func" << std::endl; }
    }
}
​
// ===== 匿名命名空间 =====
// 等价于 static,只在本文件可见
namespace
{
    int localVar = 42;   // 只在本文件可见
    void localFunc() { std::cout << "局部函数" << std::endl; }
}
​
int main()
{
    using namespace std;
​
    // 使用嵌套命名空间
    outer::inner::show();
​
    // 内联命名空间
    FifthEd::func();           // 调用 FifthEdV1::func(内联)
    FifthEd::FifthEdV1::func(); // 显式指定
    FifthEd::FifthEdV2::func(); // 显式指定
​
    // 匿名命名空间
    cout << localVar << endl;
    localFunc();
​
    return 0;
}

18.2.2 using 声明和 using 指示

复制代码
// using_demo.cpp -- using声明和指示
#include <iostream>
#include <string>
​
namespace Lib1
{
    int x = 1;
    void func() { std::cout << "Lib1::func" << std::endl; }
    class MyClass { public: void show() { std::cout << "Lib1::MyClass" << std::endl; } };
}
​
namespace Lib2
{
    int x = 2;
    void func() { std::cout << "Lib2::func" << std::endl; }
}
​
void demoUsingDeclaration()
{
    // using 声明:引入单个名字
    using Lib1::func;
    using Lib1::MyClass;
​
    func();   // Lib1::func
    MyClass obj;
    obj.show();
​
    // using Lib2::func;   // ❌ 错误!func已经被Lib1::func占用
}
​
void demoUsingDirective()
{
    // using 指示:引入整个命名空间
    using namespace Lib1;
    using namespace Lib2;
​
    // x;   // ❌ 二义性!Lib1::x 还是 Lib2::x?
    Lib1::x;   // 必须显式指定
    Lib2::x;
​
    // func();   // ❌ 二义性!
    Lib1::func();
    Lib2::func();
}
​
// ===== 命名空间与函数重载 =====
namespace NS
{
    void print(int i)    { std::cout << "NS::print(int) " << i << std::endl; }
    void print(double d) { std::cout << "NS::print(double) " << d << std::endl; }
}
​
void print(std::string s) { std::cout << "::print(string) " << s << std::endl; }
​
int main()
{
    using namespace std;
​
    demoUsingDeclaration();
    demoUsingDirective();
​
    // 实参依赖查找(ADL/Koenig查找)
    // 调用函数时,编译器会在实参类型所在的命名空间中查找
    using NS::print;
    print(42);       // NS::print(int)
    print(3.14);     // NS::print(double)
    print(string("hello"));  // ::print(string)
​
    return 0;
}

18.2.3 命名空间与类

复制代码
// namespace_class.cpp -- 命名空间与类
#include <iostream>
#include <string>
​
namespace MyLib
{
    // 类定义在命名空间中
    class Screen
    {
    public:
        using pos = std::string::size_type;
​
        Screen(pos ht, pos wd, char c)
            : height(ht), width(wd), contents(ht * wd, c) {}
​
        char get() const { return contents[cursor]; }
        Screen& move(pos r, pos c);
​
    private:
        pos         cursor = 0;
        pos         height = 0, width = 0;
        std::string contents;
    };
​
    // 在命名空间外定义成员函数
    Screen& Screen::move(pos r, pos c)
    {
        cursor = r * width + c;
        return *this;
    }
​
    // 友元函数自动成为命名空间的成员
    class Window_mgr
    {
    public:
        void clear(Screen& s)
        {
            s.contents = std::string(s.height * s.width, ' ');
        }
    };
}
​
int main()
{
    MyLib::Screen s(5, 5, 'X');
    s.move(2, 2);
    std::cout << s.get() << std::endl;
​
    return 0;
}

18.3 多重继承与虚继承

18.3.1 多重继承

复制代码
// multiple_inheritance.cpp -- 多重继承
#include <iostream>
#include <string>
​
class ZooAnimal
{
public:
    ZooAnimal() { std::cout << "[ZooAnimal构造]" << std::endl; }
    virtual ~ZooAnimal() { std::cout << "[ZooAnimal析构]" << std::endl; }
​
    virtual std::string name() const { return "ZooAnimal"; }
    void breathe() const { std::cout << "呼吸" << std::endl; }
};
​
class Endangered
{
public:
    Endangered() { std::cout << "[Endangered构造]" << std::endl; }
    virtual ~Endangered() { std::cout << "[Endangered析构]" << std::endl; }
​
    virtual std::string status() const { return "濒危"; }
    void protect() const { std::cout << "保护中" << std::endl; }
};
​
// 多重继承
class Panda : public ZooAnimal, public Endangered
{
public:
    Panda() { std::cout << "[Panda构造]" << std::endl; }
    ~Panda() { std::cout << "[Panda析构]" << std::endl; }
​
    std::string name()   const override { return "大熊猫"; }
    std::string status() const override { return "极度濒危"; }
​
    void eat() const { std::cout << "吃竹子" << std::endl; }
};
​
int main()
{
    using namespace std;
​
    cout << "===== 构造顺序 =====" << endl;
    Panda p;
​
    cout << "\n===== 使用 =====" << endl;
    p.breathe();   // ZooAnimal 的成员
    p.protect();   // Endangered 的成员
    p.eat();       // Panda 自己的成员
​
    cout << "名字:" << p.name() << endl;
    cout << "状态:" << p.status() << endl;
​
    // 多态
    ZooAnimal* za = &p;
    Endangered* en = &p;
​
    cout << "\n通过基类指针:" << endl;
    cout << za->name() << endl;   // 大熊猫(虚函数)
    cout << en->status() << endl; // 极度濒危(虚函数)
​
    cout << "\n===== 析构顺序(逆序)=====" << endl;
    return 0;
}

18.3.2 虚继承

复制代码
// virtual_inheritance.cpp -- 虚继承
#include <iostream>
#include <string>

// 菱形继承问题:
//        Animal
//       /      \
//    Tiger    Lion
//       \      /
//       Liger(狮虎兽)
// 没有虚继承时,Liger 会有两份 Animal 的数据!

class Animal
{
public:
    Animal(const std::string& name) : name_(name)
    {
        std::cout << "[Animal构造] " << name_ << std::endl;
    }
    virtual ~Animal() { std::cout << "[Animal析构]" << std::endl; }

    virtual std::string sound() const { return "..."; }
    std::string name() const { return name_; }

protected:
    std::string name_;
};

// 虚继承:解决菱形继承问题
class Tiger : virtual public Animal
{
public:
    Tiger(const std::string& name) : Animal(name)
    {
        std::cout << "[Tiger构造]" << std::endl;
    }
    ~Tiger() { std::cout << "[Tiger析构]" << std::endl; }

    std::string sound() const override { return "吼"; }
    void hunt() const { std::cout << "老虎在狩猎" << std::endl; }
};

class Lion : virtual public Animal
{
public:
    Lion(const std::string& name) : Animal(name)
    {
        std::cout << "[Lion构造]" << std::endl;
    }
    ~Lion() { std::cout << "[Lion析构]" << std::endl; }

    std::string sound() const override { return "咆哮"; }
    void roar() const { std::cout << "狮子在咆哮" << std::endl; }
};

// 最终派生类必须显式初始化虚基类
class Liger : public Tiger, public Lion
{
public:
    // 必须显式调用 Animal 的构造函数
    Liger(const std::string& name)
        : Animal(name),   // 虚基类构造函数
          Tiger(name),
          Lion(name)
    {
        std::cout << "[Liger构造]" << std::endl;
    }
    ~Liger() { std::cout << "[Liger析构]" << std::endl; }

    // 必须重写 sound(),否则二义性
    std::string sound() const override { return "特殊叫声"; }
};

int main()
{
    using namespace std;

    cout << "===== 虚继承 =====" << endl;
    Liger liger("狮虎兽");

    cout << "\n===== 使用 =====" << endl;
    cout << "名字:" << liger.name() << endl;   // 只有一份 name_
    cout << "叫声:" << liger.sound() << endl;
    liger.hunt();
    liger.roar();

    // 只有一份 Animal 数据
    Animal* ap = &liger;
    cout << "通过Animal*:" << ap->name() << endl;

    cout << "\n===== 析构 =====" << endl;
    return 0;
}

18.3.3 虚继承中的构造顺序

复制代码
// virtual_inheritance_order.cpp -- 虚继承构造顺序
#include <iostream>

class Base
{
public:
    Base(int v) : val(v)
    {
        std::cout << "Base(" << v << ")" << std::endl;
    }
    int val;
};

class D1 : virtual public Base
{
public:
    D1(int v) : Base(v)
    {
        std::cout << "D1(" << v << ")" << std::endl;
    }
};

class D2 : virtual public Base
{
public:
    D2(int v) : Base(v)
    {
        std::cout << "D2(" << v << ")" << std::endl;
    }
};

class Final : public D1, public D2
{
public:
    // 虚基类由最终派生类初始化
    // D1 和 D2 中的 Base(v) 被忽略
    Final(int v1, int v2, int vb)
        : Base(vb),   // 虚基类
          D1(v1),
          D2(v2)
    {
        std::cout << "Final" << std::endl;
    }
};

int main()
{
    // 构造顺序:
    // 1. 虚基类(Base)
    // 2. 非虚基类(D1, D2,按声明顺序)
    // 3. 最终派生类(Final)
    Final f(1, 2, 100);
    std::cout << "val = " << f.val << std::endl;   // 100(虚基类的值)

    return 0;
}

18.4 综合示例:大型程序框架

复制代码
// large_program_framework.cpp -- 综合示例
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <map>
#include <functional>
#include <stdexcept>
#include <sstream>

// ===== 命名空间组织代码 =====
namespace Framework
{
    // ===== 异常层次 =====
    class FrameworkException : public std::exception
    {
    protected:
        std::string message_;
        int         code_;

    public:
        FrameworkException(const std::string& msg, int code)
            : message_(msg), code_(code) {}

        const char* what() const noexcept override
        {
            return message_.c_str();
        }
        int code() const { return code_; }
    };

    class ConfigException : public FrameworkException
    {
    public:
        ConfigException(const std::string& key)
            : FrameworkException("配置项不存在: " + key, 1001) {}
    };

    class ServiceException : public FrameworkException
    {
    public:
        ServiceException(const std::string& service)
            : FrameworkException("服务不可用: " + service, 2001) {}
    };

    // ===== 配置管理 =====
    class Config
    {
    private:
        std::map<std::string, std::string> data_;

    public:
        void set(const std::string& key, const std::string& val)
        {
            data_[key] = val;
        }

        const std::string& get(const std::string& key) const
        {
            auto it = data_.find(key);
            if (it == data_.end())
                throw ConfigException(key);
            return it->second;
        }

        template <typename T>
        T getAs(const std::string& key) const
        {
            const std::string& val = get(key);
            std::istringstream iss(val);
            T result;
            if (!(iss >> result))
                throw FrameworkException("类型转换失败: " + key, 1002);
            return result;
        }

        bool has(const std::string& key) const
        {
            return data_.count(key) > 0;
        }
    };

    // ===== 服务接口(抽象基类)=====
    class IService
    {
    public:
        virtual ~IService() = default;
        virtual void start()   = 0;
        virtual void stop()    = 0;
        virtual bool isRunning() const = 0;
        virtual std::string name() const = 0;
    };

    // ===== 具体服务 =====
    class DatabaseService : public IService
    {
    private:
        bool running_ = false;
        std::string host_;
        int         port_;

    public:
        DatabaseService(const Config& cfg)
        {
            host_ = cfg.get("db.host");
            port_ = cfg.getAs<int>("db.port");
        }

        void start() override
        {
            std::cout << "[DB] 连接到 " << host_ << ":" << port_ << std::endl;
            running_ = true;
        }

        void stop() override
        {
            std::cout << "[DB] 断开连接" << std::endl;
            running_ = false;
        }

        bool isRunning() const override { return running_; }
        std::string name() const override { return "DatabaseService"; }

        void query(const std::string& sql) const
        {
            if (!running_)
                throw ServiceException(name());
            std::cout << "[DB] 执行:" << sql << std::endl;
        }
    };

    class CacheService : public IService
    {
    private:
        bool running_ = false;
        std::map<std::string, std::string> cache_;

    public:
        void start() override
        {
            std::cout << "[Cache] 启动缓存服务" << std::endl;
            running_ = true;
        }

        void stop() override
        {
            std::cout << "[Cache] 停止缓存服务" << std::endl;
            cache_.clear();
            running_ = false;
        }

        bool isRunning() const override { return running_; }
        std::string name() const override { return "CacheService"; }

        void set(const std::string& key, const std::string& val)
        {
            if (!running_) throw ServiceException(name());
            cache_[key] = val;
        }

        std::string get(const std::string& key) const
        {
            if (!running_) throw ServiceException(name());
            auto it = cache_.find(key);
            if (it == cache_.end())
                throw FrameworkException("缓存未命中: " + key, 3001);
            return it->second;
        }
    };

    // ===== 服务容器 =====
    class ServiceContainer
    {
    private:
        std::map<std::string, std::shared_ptr<IService>> services_;

    public:
        template <typename T, typename... Args>
        std::shared_ptr<T> registerService(Args&&... args)
        {
            auto service = std::make_shared<T>(std::forward<Args>(args)...);
            services_[service->name()] = service;
            return service;
        }

        template <typename T>
        std::shared_ptr<T> getService(const std::string& name) const
        {
            auto it = services_.find(name);
            if (it == services_.end())
                throw ServiceException(name);
            return std::dynamic_pointer_cast<T>(it->second);
        }

        void startAll()
        {
            for (auto& [name, service] : services_)
            {
                try
                {
                    service->start();
                    std::cout << name << " 启动成功" << std::endl;
                }
                catch (const std::exception& e)
                {
                    std::cerr << name << " 启动失败:" << e.what() << std::endl;
                }
            }
        }

        void stopAll()
        {
            for (auto& [name, service] : services_)
            {
                try
                {
                    if (service->isRunning())
                        service->stop();
                }
                catch (const std::exception& e)
                {
                    std::cerr << name << " 停止失败:" << e.what() << std::endl;
                }
            }
        }
    };

}   // namespace Framework

int main()
{
    using namespace std;
    using namespace Framework;

    // ===== 配置 =====
    Config cfg;
    cfg.set("db.host", "localhost");
    cfg.set("db.port", "5432");
    cfg.set("app.name", "MyApp");

    cout << "===== 配置读取 =====" << endl;
    try
    {
        cout << "db.host = " << cfg.get("db.host") << endl;
        cout << "db.port = " << cfg.getAs<int>("db.port") << endl;
        cout << cfg.get("missing.key") << endl;   // 抛出异常
    }
    catch (const ConfigException& e)
    {
        cout << "配置错误:" << e.what() << endl;
    }

    // ===== 服务容器 =====
    cout << "\n===== 服务启动 =====" << endl;
    ServiceContainer container;

    auto db    = container.registerService<DatabaseService>(cfg);
    auto cache = container.registerService<CacheService>();

    container.startAll();

    // ===== 使用服务 =====
    cout << "\n===== 使用服务 =====" << endl;
    try
    {
        db->query("SELECT * FROM users");
        cache->set("user:1", "Alice");
        cout << "缓存:" << cache->get("user:1") << endl;
        cout << "缓存:" << cache->get("user:999") << endl;   // 未命中
    }
    catch (const ServiceException& e)
    {
        cout << "服务错误:" << e.what() << endl;
    }
    catch (const FrameworkException& e)
    {
        cout << "框架错误[" << e.code() << "]:" << e.what() << endl;
    }

    // ===== 停止服务 =====
    cout << "\n===== 服务停止 =====" << endl;
    container.stopAll();

    return 0;
}

📝 第18章知识点总结

知识点 核心要点
异常抛出 throw 创建异常对象,throw; 重新抛出(保持原始类型)
栈展开 异常传播时自动调用局部对象析构函数,RAII保证资源释放
异常安全 基本保证(有效状态)、强保证(状态不变)、不抛出保证(noexcept)
noexcept 承诺不抛出,析构函数和移动操作应标记noexcept
异常类层次 继承 std::exception,重写 what(),按从具体到抽象的顺序catch
命名空间 解决命名冲突,namespace name { } 定义,:: 访问
开放命名空间 命名空间可以分多次定义,成员累积
内联命名空间 C++11,成员可直接被外层命名空间访问,用于版本管理
匿名命名空间 替代 static,限制文件内可见性
using 声明 引入单个名字,冲突时报错
using 指示 引入整个命名空间,可能导致二义性
ADL(实参依赖查找) 在实参类型所在命名空间中查找函数
多重继承 继承多个基类,构造顺序按声明顺序,析构逆序
虚继承 解决菱形继承,虚基类只有一份,最终派生类负责初始化
虚继承构造顺序 先虚基类,再非虚基类(按声明顺序),最后派生类
相关推荐
星恒随风1 小时前
C++ 类和对象入门(三):拷贝构造、赋值运算符重载和深浅拷贝
开发语言·c++·笔记·学习
Cx330❀1 小时前
【MySQL基础】库与表的全面操纵指南
linux·服务器·网络·数据库·c++·mysql
RickyWasYoung1 小时前
【Matlab】科研绘图配色-极简版
开发语言·matlab
凡人叶枫1 小时前
Effective C++ 条款03:尽可能使用 const
linux·开发语言·c++·嵌入式开发
光影6271 小时前
Python接口自动化测试----Requests库基础入门
开发语言·python·测试工具·pycharm·自动化
程序媛_1 小时前
【Python】连接PostgreSQL获取手机验证码
开发语言·python·postgresql
ch.ju1 小时前
Java Programming Chapter 4——Inherited call
java·开发语言
信看1 小时前
Jetson Orin Quectel QMI 拨号上网
开发语言·python
小欣加油1 小时前
Leetcode31 下一个排列
数据结构·c++·算法·leetcode·职场和发展