[Effective C++]条款18:让接口容易被正确使用,不易被误用

.
C++中的接口实现有 function接口、class接口和template接口等,每一种接口都是用户与代码互动的方式。为了开发一个“容易被正确使用,不容易被误用”的接口,有如下几种方式:

1、使用外覆类型增强使用规范

  • 如下Date的构造函数设计,与错误使用
class Date{
public:
    Date(int month,int day,int year);
    ...
};

int main(){
    Data d(30,3,1995); // 本来想输入的是3月30号,但却传递了一个无效的日期
    return 0;
}
  • 外覆类型通过为month,day和year分别创建不同的类型,保证在编译时规避错误,同时让代码更易读和理解。
    • explicit关键字,可防止隐式转换
#include <iostream>
#include <stdexcept>

// 定义外覆类型
struct Month {
    explicit Month(int m) : val(m) {
        if (m < 1 || m > 12) {
            throw std::invalid_argument("Month must be between 1 and 12");
        }
    }
    int val;
};

struct Day {
    explicit Day(int d) : val(d) {
        if (d < 1 || d > 31) {
            throw std::invalid_argument("Day must be between 1 and 31");
        }
    }
    int val;
};

struct Year {
    explicit Year(int y) : val(y) {}
    int val;
};

// Date 类
class Date {
public:
    Date(Month month, Day day, Year year)
        : month_(month), day_(day), year_(year) {}

    void print() const {
        std::cout << "Date: " << month_.val << "/" << day_.val << "/" << year_.val << std::endl;
    }

private:
    Month month_;
    Day day_;
    Year year_;
};

int main() {
    try {
        // 使用外覆类型创建 Date 对象
        Date date(Month(10), Day(25), Year(2023));
        date.print();
        Date date(Month(13), Day(25), Year(2023));  // 抛出异常,月份无效
    } catch (const std::invalid_argument& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

2、使用枚举类型

  • 通过menu class代替普通的emnu,避免枚举值的隐式转换和命名冲突
enum class Color { Red, Green, Blue };

void setColor(Color color) {
    switch (color) {
        case Color::Red:   std::cout << "Red\n"; break;
        case Color::Green: std::cout << "Green\n"; break;
        case Color::Blue:  std::cout << "Blue\n"; break;
    }
}

int main() {
    setColor(Color::Red);  // 正确
    // setColor(0); // 错误:无法通过编译
}

3、使用资源管理类

  • 使用智能指针std::unique_ptr和std::shared_ptr来管理动态内存,避免函数返回值的内存泄漏和悬空指针
std::unique_ptr<int> createInt(int value) {
    return std::make_unique<int>(value);
}

std::shared_ptr<int> createSharedInt(int value) {
    return std::make_shared<int>(value);
}

int main() {
    auto ptr = createInt(42);
    auto sharedPtr = createSharedInt(42);
}

4、使用RAII技术

  • RAII方面用于资源管理的技术,如内存,文件句柄等,通过对象的生命周期来管理资源的获取和释放,避免资源泄漏。
class File {
public:
    File(const std::string& filename) : file_(fopen(filename.c_str(), "r")) {
        if (!file_) throw std::runtime_error("Failed to open file");
    }
    ~File() { if (file_) fclose(file_); }
    FILE* get() const { return file_; }
private:
    FILE* file_;
};

void readFile(const std::string& filename) {
    File file(filename);
    // 使用 file.get() 读取文件
}

思维导图笔记:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值