C++ 命名空间与模板

解决命名冲突 + 泛型编程利器。


一、命名空间(namespace)

1.1 为什么需要命名空间

随着项目规模增大,命名冲突几乎不可避免:

  • 自己写的 strcat() 会覆盖标准库的 strcat()
  • 两个第三方库可能都定义了 string
  • 多人协作时函数名、类名容易撞车

命名空间的本质: 给标识符加一个"姓氏",把全局作用域拆成独立的小房间,同名标识符在不同房间里互不干扰。

namespace 名称 {
    // 声明
}

在命名空间中定义的任何东西都局限于该命名空间内。

1.2 基础用法

#include <iostream>
#include <iomanip>
using namespace std;

namespace Onespace { // 第一命名空间
    void print() {
        cout << "执行Onespace名字空间的print()函数" << endl;
    }
}

namespace Twospace { // 第二命名空间
    void print() {
        cout << "执行Twospace名字空间的print()函数" << endl;
    }
}

using namespace Twospace; // 引入 Twospace,使其成员可直接使用

int main() {
    Onespace::print();  // 通过 :: 限定访问 Onespace
    Twospace::print();  // 通过 :: 限定访问 Twospace(不用 using 也行)
    print();            // 由于 using 了 Twospace,直接调用
    print();
    return 0;
}

:: 叫作用域解析运算符,命名空间::成员,就像一个门牌号。

运行结果

命名空间基础运行结果

1.3 嵌套命名空间

命名空间可以嵌套,像文件夹套文件夹:

namespace 命名空间名称1 {
    // 代码声明
    namespace 命名空间名称2 {
        // 代码声明
    }
}

示例:

#include <iostream>
#include <iomanip>
using namespace std;

namespace Onespace {
    void print() {
        cout << "执行Onespace名字空间的print()函数" << endl;
    }

    namespace Twospace { // 嵌套在 Onespace 内部
        void print() {
            cout << "执行Twospace名字空间的print()函数" << endl;
        }
    }
}

using namespace Onespace::Twospace; // 只引入嵌套的 Twospace

int main() {
    print(); // 调用 Onespace::Twospace::print()
    return 0;
}

访问嵌套成员Onespace::Twospace::print(),用 :: 逐层穿透。

运行结果

嵌套命名空间运行结果

1.4 using 指令小结

写法 效果 推荐度
using namespace std; 整个命名空间全部引入 学习时方便,大项目慎用
using std::cout; 只引入单个成员 精准,推荐
std::cout 不用 using,每次写全名 最安全

二、模板(Template)

泛型编程的核心:写一份代码,适配多种类型。模板是创建泛型类或函数的蓝图。

2.1 函数模板

template <typename T>
返回类型 函数名(参数列表) {
    // 函数主体
}

T 是类型占位符,编译时会被实际类型替换。

示例:求两数最大值

#include <iostream>
#include <string>
using namespace std;

template <typename T>
inline T const& MaxFunc(T const& a, T const& b) {
    return a > b ? a : b;
}

int main() {
    int i = 90, j = 100;
    cout << "int类型MaxFunc(i,j)=" << MaxFunc(i, j) << endl;

    double f1 = 10.1, f2 = 20.115;
    cout << "double类型MaxFunc(i,j)=" << MaxFunc(f1, f2) << endl;

    string s1 = "helloworld", s2 = "goodbye";
    cout << "string类型MaxFunc(i,j)=" << MaxFunc(s1, s2) << endl;
    return 0;
}

inline 建议编译器内联展开,省去函数调用开销。这里用 const& 避免了不必要的拷贝。

运行结果

函数模板运行结果

2.2 类模板

template <class T>
class 类名 {
    // 使用 T 作为类型占位符
};

多个泛型参数用逗号分隔:template <class T1, class T2>

示例:比较两个数

#include <iostream>
#include <string>
using namespace std;

template <typename T>
class CompareSS {
public:
    CompareSS(T a, T b) {
        x = a;
        y = b;
    }
    T maxfunc() {
        return (x > y ? x : y);
    }
private:
    T x, y; // 成员变量也使用模板类型
};

int main() {
    CompareSS<int> obj1(30, 90);
    cout << "int最大值为:" << obj1.maxfunc() << endl;

    CompareSS<double> obj2(30.12346, 90.123);
    cout << "double最大值为:" << obj2.maxfunc() << endl;
    return 0;
}

实例化时必须指定类型:CompareSS<int>CompareSS<double>。编译器会为每种类型生成一份独立的类代码。

运行结果

类模板运行结果


三、核心要点总结

知识点 一句话
命名空间 给标识符分区,避免同名冲突;用 :: 访问
嵌套命名空间 命名空间里套命名空间,A::B::func() 逐层穿透
using 指令 偷懒写法,大项目建议 using 单个成员 或写全名
函数模板 template <typename T> 让函数适配任意类型
类模板 template <class T> 让类适配任意类型,实例化时指定

记忆口诀

  • 命名空间 = 姓氏:王家::张三 和 李家::张三 不是同一个人
  • 模板 = 模具:一套模具,灌什么材料出什么产品
  • typenameclass 在模板参数里基本等价,混用看习惯

更多推荐