上篇讲了模板函数,今天进一步——模板类。

模板类在面试里的出镜率比模板函数高得多。因为STL容器全是模板类实现的,面试官问你vector、map、unordered_map的底层原理,本质上都在考模板类的设计思路。

讲个面试场景。

面试官问:"你用过vector吧?vector、vector、vector都能用,它底层是怎么做到的?"

如果你回答"模板",面试官会点头,然后追问:"那你手写一个简单的模板类试试?"

很多人就卡住了。

今天把模板类从语法到实战一次讲透。

模板类的基本语法

手写一个简单的动态数组:

template<typename T>
class SimpleVector {
    T* data_;
    int size_;
    int capacity_;
public:
    SimpleVector() : data_(nullptr), size_(0), capacity_(0) {}
    
    void push_back(const T& value) {
        if (size_ == capacity_) {
            int new_cap = capacity_ == 0 ? 1 : capacity_ * 2;
            T* new_data = new T[new_cap];
            for (int i = 0; i < size_; i++) {
                new_data[i] = data_[i];
            }
            delete[] data_;
            data_ = new_data;
            capacity_ = new_cap;
        }
        data_[size_++] = value;
    }
    
    T& operator[](int index) { return data_[index]; }
    int size() const { return size_; }
    
    ~SimpleVector() { delete[] data_; }
};

用法和std::vector一样:

SimpleVector<int> nums;
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);
cout << nums[0] << endl;  // 输出: 1

SimpleVector<double> values;
values.push_back(3.14);

注意一个关键点:模板类的成员函数定义通常也放在头文件里,和模板函数一样。因为编译器在实例化时需要看到完整定义。

模板类的实例化机制

模板类跟普通类最大的区别是:模板类本身不是一个"真正的类",它只是一个生成类的"蓝图"。

当你写SimpleVector<int>的时候,编译器把蓝图里所有的T替换成int,生成一个具体的类。这个过程叫模板实例化

SimpleVector<int>    → 编译器生成 SimpleVector_int(所有T换成int)
SimpleVector<double> → 编译器生成 SimpleVector_double(所有T换成double)

每个不同的类型参数,编译器都会生成一份独立的代码。所以SimpleVector<int>和SimpleVector<double>是两个完全不同的类,它们之间没有任何关系。

这一点很重要。你不能把SimpleVector<int>*赋值给SimpleVector<double>*,虽然它们来自同一个模板,但实例化后就是两个独立的类型。

在机器人开发里怎么用模板类

在机器人开发里,模板类最常见的应用是数据结构。

比如你需要一个点云数据的容器,不同传感器返回的点类型不一样:

template<typename PointT>
class PointCloud {
    vector<PointT> points_;
    string frame_id_;
    uint64_t timestamp_;
public:
    void addPoint(const PointT& p) { points_.push_back(p); }
    size_t size() const { return points_.size(); }
    const PointT& operator[](size_t i) const { return points_[i]; }
    void setFrameId(const string& id) { frame_id_ = id; }
};

struct PointXYZ { float x, y, z; };
struct PointXYZRGB { float x, y, z; uint8_t r, g, b; };

PointCloud<PointXYZ> cloud1;
PointCloud<PointXYZRGB> cloud2;

PCL(Point Cloud Library)就是这么设计的。如果你用过PCL,pcl::PointCloud<pcl::PointXYZ>就是模板类的典型用法。

类模板的特化

和模板函数一样,模板类也可以特化——为特定类型提供不同的实现。

// 通用版本
template<typename T>
class DataParser {
public:
    T parse(const string& data) {
        // 通用解析逻辑
        return T();
    }
};

// string的特化版本
template<>
class DataParser<string> {
public:
    string parse(const string& data) {
        // string不需要解析,直接返回
        return data;
    }
};

// int的特化版本
template<>
class DataParser<int> {
public:
    int parse(const string& data) {
        return stoi(data);
    }
};

在机器人开发里,传感器数据的解析就经常需要特化。不同传感器的数据格式不一样,用模板特化可以为每种数据类型提供专门的解析逻辑,同时保持统一的接口。

面试中的模板类考点

面试官考模板类,有几个高频问题。

第一个:"模板类和普通类有什么区别?"核心回答:模板类是类的蓝图,需要实例化后才能使用;每个实例化版本是独立的类;定义通常要放在头文件里。

第二个:"模板类的静态成员变量怎么工作?"每个实例化版本有自己独立的静态成员。SimpleVector<int>::count和SimpleVector<double>::count是两个不同的变量。

template<typename T>
class Counter {
public:
    static int count;
};

template<typename T>
int Counter<T>::count = 0;

Counter<int>::count = 10;
Counter<double>::count = 20;
// 两个count互不影响

第三个:"模板类能不能有非模板成员?"可以。模板类里可以有普通成员函数和普通成员变量,它们不受模板参数影响。

再聊一个面试高频追问:模板类的全特化和偏特化有什么区别?全特化是针对所有模板参数都指定了具体类型,比如template<> class SimpleVector<bool>,为bool类型做一个特殊版本。偏特化是只指定部分参数,比如template<typename T> class SimpleVector<T*>,专门处理指针类型。偏特化在实际项目中用得比全特化更多,比如STL的std::iterator_traits就大量使用了偏特化来提取不同类型迭代器的特征。面试时如果你能举出偏特化的实际应用例子,而不是只停留在语法层面,面试官会认为你对模板编程有比较深入的理解,而不只是会背概念。

给正在准备面试的你一点建议

模板类在面试里考得比模板函数多,因为STL容器就是模板类。

最基础的要求:能手写一个简单的模板类,理解实例化的概念。

进阶要求:知道模板特化,能解释为什么模板定义要放头文件。

如果你能把vector的简化版写出来(就像今天这个SimpleVector),面试官对你的评价会很高。因为这说明你不仅会用STL,还理解它的设计思路。

下篇讲异常处理try/catch——机器人系统的容错基础。从C++基础语法进入工程实践的领域了。


如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。

「机器人软件开发面试·从入门到精通」连载系列 

上一篇:第26篇 模板函数——写通用算法的利器

下一篇预告:第28篇 异常处理try/catch——机器人系统的容错基础

有任何问题欢迎评论区留言,我会尽量回复。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐