You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++:如何从模板类派生并重载构造函数?及自定义vector对象计数

解决你的vector模板类需求:别名、对象计数与派生重载

1. 给vector<double,2>指定类型别名

给模板特化类型起别名非常简单,C里有两种常用方式,其中C11及以后推荐的using语法更直观,尤其适合复杂模板场景:

// 方式1:传统typedef
typedef vector<double, 2> Vec2d;

// 方式2:using(更推荐,可读性更强)
using Vec2d = vector<double, 2>;

之后你就可以用Vec2d代替冗长的vector<double,2>声明变量,比如Vec2d my_vec;。

2. 统计对象总数与存活数

要统计特定模板特化(比如Vec2d)的对象总数和存活数,我们需要在模板类中添加静态成员变量——每个模板特化都是独立类型,它们的静态成员会各自维护独立的计数。

修改你的模板类,添加静态成员并在构造/析构中更新计数:

#include <iostream>

// 注意把size改成size_t,和标准库的类型规范保持一致
template<typename T, size_t S>  
class vector{
protected:  // 改成protected方便派生类访问(如果需要的话)
    T *_values;
private:
    // 静态成员:统计当前类型的总创建数和存活数
    static size_t total_objects;
    static size_t live_objects;
public:
    // 简化默认构造:用new T[S]()直接完成值初始化
    vector(): _values(new T[S]()){  
        total_objects++;
        live_objects++;
    }

    // 拷贝构造也要更新计数(如果需要支持拷贝)
    vector(const vector& other): _values(new T[S]){
        for(size_t i = 0; i < S; i++){
            _values[i] = other._values[i];
        }
        total_objects++;
        live_objects++;
    }

    // 移动构造同理,避免空指针重复delete
    vector(vector&& other) noexcept: _values(other._values){
        other._values = nullptr;
        total_objects++;
        live_objects++;
    }

    ~vector(){
        if(_values != nullptr){
            delete[] _values;
            live_objects--;
        }
    }

    // 封装静态计数的获取方法,比直接访问成员更符合封装原则
    static size_t get_total_count(){
        return total_objects;
    }

    static size_t get_live_count(){
        return live_objects;
    }
};

// C++17前必须在类外定义模板的静态成员,C++17后可使用inline静态成员省略这一步
template<typename T, size_t S>
size_t vector<T, S>::total_objects = 0;

template<typename T, size_t S>
size_t vector<T, S>::live_objects = 0;

测试Vec2d的计数效果:

int main(){
    using Vec2d = vector<double, 2>;

    std::cout << "Total: " << Vec2d::get_total_count() << ", Live: " << Vec2d::get_live_count() << std::endl;  // 输出 0,0

    Vec2d v1;
    std::cout << "Total: " << Vec2d::get_total_count() << ", Live: " << Vec2d::get_live_count() << std::endl;  // 输出 1,1

    {
        Vec2d v2;
        std::cout << "Total: " << Vec2d::get_total_count() << ", Live: " << Vec2d::get_live_count() << std::endl;  // 输出 2,2
    }  // v2超出作用域析构,存活数减1

    std::cout << "Total: " << Vec2d::get_total_count() << ", Live: " << Vec2d::get_live_count() << std::endl;  // 输出 2,1

    return 0;
}

⚠️注意:如果你的类需要支持拷贝、移动操作,一定要在对应的构造函数中更新计数,否则统计结果会不准确。

3. 从模板类派生并重载构造函数

从模板类派生的核心是明确基类的模板参数,同时在派生类构造函数中正确调用基类构造。比如我们派生一个支持初始化列表的MyVector:

#include <initializer_list>
#include <stdexcept>

template<typename T, size_t S>
class MyVector : public vector<T, S>{
public:
    // 重载构造:用初始化列表初始化元素
    MyVector(std::initializer_list<T> init) : vector<T, S>(){  // 先调用基类默认构造
        if(init.size() != S){
            throw std::invalid_argument("初始化列表长度和vector大小不匹配!");
        }
        size_t i = 0;
        for(const auto& val : init){
            this->_values[i++] = val;
        }
    }

    // 重载构造:用单个值初始化所有元素
    MyVector(const T& val) : vector<T, S>(){
        for(size_t i = 0; i < S; i++){
            this->_values[i] = val;
        }
    }
};

使用这个派生类:

int main(){
    MyVector<double, 2> v({1.5, 3.2});  // 用初始化列表构造二维向量
    MyVector<int, 3> v2(7);  // 三维向量所有元素初始化为7
    return 0;
}

如果不想把基类的_values改成protected,也可以在基类中添加公有的元素设置方法(比如void set(size_t idx, const T& val)),这样更符合封装的设计原则。


内容的提问来源于stack exchange,提问作者pjoter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:56:51