如何让基类中的类型别名对派生类不可见?
问题:如何让基图类的内部类型别名仅对基类可见,不暴露给派生类?
我有一组采用CRTP模式与派生图类协作的基图类:定义了一个以派生图类为模板参数的模板类GraphTypes,而Edge、Node等基图类则以GraphTypes作为模板参数。
在基图类内部,我用using定义了类型别名来简化代码,但希望这些别名仅在基类内部可见,对派生类不可见,请问这可行吗?
下面是代码示例,以及派生类中误用基类类型别名的问题:
namespace DirectedGraph { template<class NodeT, class EdgeT> class GraphTypes { public: using NodeType = NodeT; using EdgeType = EdgeT; }; template<class GraphTypes> class Edge { private: using NodeType = typename GraphTypes::NodeType; using EdgeType = typename GraphTypes::EdgeType; public: auto This() -> EdgeType&; }; } namespace MyGraph { class Node; class Edge; using GraphTypes = DirectedGraph::GraphTypes<Node, Edge>; enum class EdgeType { A, B, C }; class Edge : public DirectedGraph::Edge<GraphTypes> { Edge(EdgeType Type); // 这里的`EdgeType`被解析为基类`DirectedGraph::Edge`的私有类型别名,而非当前命名空间的枚举`MyGraph::EdgeType` }; }
可行的解决方案
方案1:移除基类的类级类型别名,改为直接使用GraphTypes的类型
把基类中类作用域的using去掉,在需要的地方直接引用GraphTypes的公开类型。这样基类不会向派生类暴露任何额外的类型别名:
namespace DirectedGraph { template<class NodeT, class EdgeT> class GraphTypes { public: using NodeType = NodeT; using EdgeType = EdgeT; }; template<class GraphTypes> class Edge { public: // 直接使用GraphTypes的类型,不定义类级别名 auto This() -> typename GraphTypes::EdgeType&; private: // 如果内部成员函数需要简化写法,可以在函数内部定义局部别名 void internalProcess() { using NodeType = typename GraphTypes::NodeType; NodeType* node = /* ... */; } }; }
方案2:用匿名命名空间隐藏基类内部别名
在基类的私有区域用匿名命名空间包裹类型别名,这些别名仅在基类内部可见,派生类无法访问:
namespace DirectedGraph { template<class NodeT, class EdgeT> class GraphTypes { public: using NodeType = NodeT; using EdgeType = EdgeT; }; template<class GraphTypes> class Edge { public: auto This() -> typename GraphTypes::EdgeType&; private: // 匿名命名空间内的别名仅当前基类实例可见 namespace { using NodeType = typename GraphTypes::NodeType; using EdgeType = typename GraphTypes::EdgeType; } void internalFunc(NodeType* node) { // 内部可以正常使用这些别名 } }; }
方案3:在派生类中明确限定名字作用域
如果不想修改基类代码,在派生类中使用自己的EdgeType时,直接加上命名空间限定,避免名字查找冲突:
namespace MyGraph { // ... 其他代码 ... class Edge : public DirectedGraph::Edge<GraphTypes> { Edge(MyGraph::EdgeType Type); // 明确指定是当前命名空间的枚举 }; }
总结
要让基类的类型别名完全对派生类不可见,最可靠的方式是不在基类的类作用域定义这些别名——要么移到函数局部使用,要么用匿名命名空间隐藏。如果只是临时解决当前的名字冲突,直接在派生类中限定作用域是最快捷的办法。
内容的提问来源于stack exchange,提问作者Magnar Myrtveit
相关产品推荐
相关产品推荐

