用template来替代重载

本文主要探讨C++中重载和泛型编程。重载可实现支持多种输入类型的函数,为用户带来便利、提高代码复用效率,但加重开发者负担。而泛型编程能将类型泛化,可应用于更多类型,只要求输入类型符合某些特性,还能“泛”常数,包括默认模板参数、特化等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

by Yazy -- 2005, 04.23

如果我们要实现一个支持多种输入类型的函数,在C++里我们可以
使用“重载”:
    void test(int n)
    {
        cout<<"test(int): "<<n<<endl;
    }

    void test(float n)
    {
        cout<<"test(float): "<<n<<endl;
    }

    void test(short n)
    {
        cout<<"test(short): "<<n<<endl;
    }
重载的思想是为每一种特定的类型去实现一个函数实体。这种方
式可能会给函数的使用者带来极大的便利,这种便利体现在用户
只须记住一个函数,而不必去为不同的类型选用其特定的函数调
用,因为“重载”的实现方式将这种“选择”定性地交给了编绎
器做了。所以“重载”是有助于用户使用函数来开发程序的,有
助于代码复用效率。

而重载的缺点是:它加重了函数开发者的开发负担。按“以用户
为中心”的思想,重载牺牲开发者更多的时间与精力,换来更多
的用户利益。函数作者需要负出更多的努力,体现于作者要写多
个版本的同一个函数;作者要保证函数的每一个版本都具有正确
或者通常是一致的语义。可能开发者要为这个保证负出更多,有
时候复杂的问题使得这种保证变得不那么有意义。

C++的template可以将要用到的类型泛化。比如在一个函数可能用
到一种未确知的类型 T,它可能是 int、float、short 或是某个
自定义类型。Template 可以让开发者使用这种“未知”,将这种
“未知”状态保留至函数被使用并且代码被编绎。 这种“未知”
的类型便是“泛化的类型”,使用这种编程范式的程序被称作“
泛型程序”。

上面的 test 使用泛型编程方式来作便可能是:
    template<class T>
    void test(T n)
    {
        cout<<"template<class T> void test(T): "<<n<<endl;
    }

相比于“重载”,泛型的函数可以应用于更多的类型,甚至常常很难
确定它可以被用于多少种类型,而重载函数通常被使用于极有限数量
的类型。

泛型函数通常只要求输入类型符合某些特性,而不理会其具体是什么
类型。例如,某个泛型函数可能要求输入类型必须可以参加算术运算、
逻辑运算或是某种接口(例如 STL 里的 iterator)。

在C++里泛型还可以“泛”常数,即将“未知”状态赋予一种常数:
    template<class T, int SIZE>
    void test(T n)
    {
        int nums[SIZE];
        //...
        cout<<"Size: "<<SIZE<<endl
            <<"Para: "<<n<<endl;
    }

泛型还包括:默认模板参数、特化等。有待学习……

### Qt 中通过重载左移运算符实现 `qDebug` 风格输出重定向 为了实现在 Qt 中通过重载左移运算符 `< <` 来让 `printinfo` 函数获取字符串并将其写入文件,可以按照以下方法设计解决方案。此方案基于 C++ 运算符重载原理以及 Qt 提供的相关工具。 --- #### 1. **创建自定义流类** 由于标准库中的 `std::ostream` 或者 Qt 的 `QDebug` 是不可修改的封闭类,因此需要构建一个自定义流类来拦截和处理输出内容。 ```cpp class CustomStream { public: template<typename T> CustomStream& operator<<(const T& value) { buffer_ += QString::number(value); // 转换为字符串并追加到缓冲区 return *this; } CustomStream& operator<<(const QString& str) { buffer_ += str; // 处理 QString 类型的内容 return *this; } ~CustomStream() { printinfo(buffer_.toUtf8().constData()); // 析构时调用 printinfo 并清空缓存 } private: QString buffer_; // 缓冲区用于暂存待写入的内容 }; ``` 以上代码实现了: - 自定义流类 `CustomStream` 支持多种类型的输入操作。 - 当对象销毁时(即表达式结束),自动调用 `printinfo` 方法完成最终的日志记录[^5]。 --- #### 2. **重新定义宏以替代原生 qDebug 行为** 接下来需要调整现有的宏定义使得每次调用看起来像普通的 `qDebug()` 使用方式一样自然流畅。 ```cpp #define shuchu CustomStream() ``` 此时任何地方只要书写类似下面这样的语句即可触发整个流程: ```cpp shuchu << "一行信息" << 42; ``` 这实际上是实例化了一个临时的 `CustomStream` 对象,并依次向它发送各个片段直到整条命令解析完毕为止;最后随着作用域退出而清理资源期间执行真正的持久化动作[^6]。 --- #### 3. **完善 printinfo 函数逻辑** 之前提到过的 `printinfo` 应当被改造得更加通用一些以便适应来自不同源头的数据源接入需求。 ```cpp #include <QFile> #include <QTextStream> void printinfo(const char* message) { static QFile logFile("application.log"); if (!logFile.isOpen()) { logFile.open(QIODevice::WriteOnly | QIODevice::Append); } QTextStream stream(&logFile); stream << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << " - " << message << "\n"; } ``` 此处改进点包括但不限于: - 添加静态局部变量确保单例模式下多次打开效率更高; - 增强时间戳格式便于后续分析追踪问题所在位置及时刻[^7]。 --- ### 示例完整代码展示 综合上述各部分形成如下完整的演示版本: ```cpp #include <QObject> #include <QString> #include <QFile> #include <QTextStream> #include <QDateTime> // 定义全局辅助函数 void printinfo(const char* message); // 创建自定义流处理器 class CustomStream { public: template<typename T> CustomStream& operator<<(const T& value){ buffer_ += QString::number(value).append(' '); return *this; } CustomStream& operator<<(const QString& str){ buffer_ += str.append(' '); return *this; } ~CustomStream(){ printinfo(buffer_.trimmed().toUtf8().constData()); } private: QString buffer_; }; // 替代原有的 qDebug 接口行为 #define shuchu CustomStream() // 实际日志保存入口 void printinfo(const char* message){ static QFile logfile("app_log.txt"); if(!logfile.isOpen()){ logfile.setFileName("app_log.txt"); logfile.open(QIODevice::WriteOnly|QIODevice::Append|QIODevice::Text); } QTextStream outstream(&logfile); outstream << QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss.zzz]") << ": "<<message<<"\n"; } int main(int argc, char *argv[]){ QObject obj; shuchu << "这是一个测试消息." << 12345; shuchu << "Another line with number:" << 98765; return 0; } ``` --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值