如何合并C++中使用不同随机分布的两个向量填充函数?
嘿,这个问题问得很到位!你完全可以通过模板或者**多态(基类指针)**来合并这两个重复的填充函数,两种方案各有优劣,我给你详细拆解一下:
方案一:模板(最简洁直接的选择)
模板是这个场景下的最优解——它能让你把重复的循环逻辑抽出来,只需要针对不同的分布和向量类型做适配,代码量更少,还能保持类型安全。
你可以在RandomVec类里写一个私有模板函数作为核心逻辑,然后让原来的两个填充函数调用它:
#include <iostream> #include <random> #include <vector> using namespace std; class RandomVec{ private: unsigned seed = 0; std::default_random_engine generator{seed}; std::normal_distribution<> rnorm{0,1}; std::uniform_int_distribution<> runifInt{0,1}; // 通用模板:把填充逻辑抽出来,接受分布和向量 template<typename DistType, typename VecType> void fillVec(vector<VecType>& v, DistType& dist) { for(auto& elem : v) { elem = dist(generator); } } public: // 原来的接口可以保留,内部调用模板 void fillRandomVecInt(vector<int>& v) { fillVec(v, runifInt); } void fillRandomVecNorm(vector<double>& v) { fillVec(v, rnorm); } // 也可以直接对外暴露模板接口,支持自定义分布(可选) template<typename DistType, typename VecType> void fillRandomVec(vector<VecType>& v, DistType& dist) { fillVec(v, dist); } }; int main() { RandomVec rv; vector<double> x(10); rv.fillRandomVecNorm(x); vector<int> y(10); rv.fillRandomVecInt(y); // 如果暴露了通用模板,还能自己传分布使用 // std::uniform_real_distribution<> runifReal(0.0, 1.0); // vector<double> z(10); // rv.fillRandomVec(z, runifReal); return 0; }
这个方案的好处:
- 完全消除了代码重复,循环逻辑只写一次
- 编译器自动推导类型,没有额外运行时开销
- 扩展性强,以后加新的分布(比如均匀实数分布),只需要加个成员变量,不用写新的填充函数
方案二:多态(基类指针,支持运行时动态切换)
如果你的需求是在运行时动态切换随机分布,那多态方案更合适。不过因为C++标准库的分布类没有共同基类,你需要自己封装一层抽象:
#include <iostream> #include <random> #include <vector> #include <memory> using namespace std; // 抽象基类:定义分布的统一接口 class BaseDistribution { public: virtual ~BaseDistribution() = default; // 虚析构函数,确保子类正确销毁 virtual double generate(default_random_engine& gen) = 0; // 纯虚函数,生成随机数 }; // 封装正态分布 class NormalDist : public BaseDistribution { private: normal_distribution<> dist; public: NormalDist(double mean, double stddev) : dist(mean, stddev) {} double generate(default_random_engine& gen) override { return dist(gen); } }; // 封装均匀整数分布 class UniformIntDist : public BaseDistribution { private: uniform_int_distribution<> dist; public: UniformIntDist(int min, int max) : dist(min, max) {} double generate(default_random_engine& gen) override { return static_cast<double>(dist(gen)); } }; class RandomVec{ private: unsigned seed = 0; std::default_random_engine generator{seed}; unique_ptr<BaseDistribution> current_dist; // 用智能指针持有当前分布 public: // 设置当前使用的分布(运行时切换) void setDistribution(unique_ptr<BaseDistribution> dist) { current_dist = move(dist); } // 通用填充函数,适配任意向量类型 template<typename VecType> void fillRandomVec(vector<VecType>& v) { if (!current_dist) { throw runtime_error("请先设置随机分布!"); } for(auto& elem : v) { elem = static_cast<VecType>(current_dist->generate(generator)); } } }; int main() { RandomVec rv; vector<double> x(10); rv.setDistribution(make_unique<NormalDist>(0, 1)); rv.fillRandomVec(x); vector<int> y(10); rv.setDistribution(make_unique<UniformIntDist>(0, 1)); rv.fillRandomVec(y); return 0; }
这个方案的特点:
- 可以在运行时随时切换分布(比如根据用户输入选择用正态还是均匀分布)
- 代码量稍大,需要额外封装分布子类
- 因为涉及虚函数调用和类型转换,会有一点点运行时开销(一般场景下可以忽略)
总结
- 如果只是想合并现有两个函数、消除代码重复,模板方案是首选,简单高效
- 如果需要运行时动态切换分布,再考虑多态方案
内容的提问来源于stack exchange,提问作者DrBombe
相关产品推荐
相关产品推荐

