如何从以派生类内部定义类型为参数的模板类继承?
如何让派生类内部定义的类型作为基类模板的参数?
我希望从一个模板类继承,该模板类的类型参数由派生类内部定义。不想使用组合方式,因为这样要么需要将vector设置为公有访问,要么得为每个对象编写方法来按预期操作vector。
请问有没有办法让示例中的第二种代码方案可行?(我知道可以像注释中的方案1那样在类外声明结构体,但我想了解是否有技巧能按方案2的方式实现)
#include <vector> #include <iostream> class Interface { public: virtual void populate() = 0; }; template<typename T> class Series : Interface { public: T methodIwantToWriteOnce(int i) const { return mVec[i]; } protected: std::vector<T> mVec; }; class SeriesInt : public Series<int> { public: virtual void populate() override { mVec.push_back(42); } }; /* 1) Working solution but outside the class */ // struct Coord // { // double x = 0.0; // double y = 0.0; // }; // class SeriesCoord : public Series<Coord> // { // public: // virtual void populate() override { mVec.push_back({42.0, 42.0}); } // }; /* 2) Impossible solution ? */ // Forward declaration class SeriesCoord; struct SeriesCoord::Coord; //useless I know but you see the idea class SeriesCoord : public Series<SeriesCoord::Coord> { public: struct Coord { double x = 0.0; double y = 0.0; }; virtual void populate() override { mVec.push_back({42.0, 42.0}); } }; int main(int argc, char *argv[]) { SeriesInt s1; s1.populate(); std::cout << s1.methodIwantToWriteOnce(0) << std::endl; SeriesCoord s2; s2.populate(); std::cout << s2.methodIwantToWriteOnce(0).x << std::endl; return 0; }
可以通过调整基类模板的设计,用「标签类型」的方式间接获取派生类内部的类型,从而实现你的需求。核心思路是让基类模板接受派生类本身作为参数,然后通过派生类的内部类型别名来获取实际要使用的类型,利用C++的依赖类型延迟解析特性避免编译错误。
修改后的可运行代码如下:
#include <vector> #include <iostream> class Interface { public: virtual void populate() = 0; }; // 修改基类模板,接受标签类型,通过标签获取实际类型 template<typename Tag> class Series : Interface { public: // 依赖类型,编译器会延迟到Tag完全定义后解析 using T = typename Tag::type; T methodIwantToWriteOnce(int i) const { return mVec[i]; } protected: std::vector<T> mVec; }; class SeriesInt : public Series<SeriesInt> { public: // 为基类提供类型别名 using type = int; virtual void populate() override { mVec.push_back(42); } }; // 现在可以在派生类内部定义Coord了 class SeriesCoord : public Series<SeriesCoord> { public: struct Coord { double x = 0.0; double y = 0.0; }; // 为基类提供类型别名,指向内部定义的Coord using type = Coord; virtual void populate() override { mVec.push_back({42.0, 42.0}); } }; int main(int argc, char *argv[]) { SeriesInt s1; s1.populate(); std::cout << s1.methodIwantToWriteOnce(0) << std::endl; SeriesCoord s2; s2.populate(); std::cout << s2.methodIwantToWriteOnce(0).x << std::endl; return 0; }
原理说明:
- 基类模板
Series不再直接接受具体类型T,而是接受一个「标签」类型(这里就是派生类本身)。 - 通过
typename Tag::type声明依赖类型,C++编译器会延迟对这个类型的解析,直到Tag(即派生类)完全定义完成,此时派生类内部的type别名和嵌套结构体已经存在。 - 派生类只需要添加
using type = 内部类型;的别名声明,就能让基类获取到需要的类型。
这样既满足了「在派生类内部定义类型」的需求,又不需要将类型暴露到类外,同时保留了继承的方式和基类的通用方法。
内容的提问来源于stack exchange,提问作者NiHoT
相关产品推荐
相关产品推荐

