基类构造函数using声明设为私有仍可构造,operator[]却需公有?
派生类中using声明基类构造函数与operator[]的可访问性差异解析
先来看你给出的代码示例:
#include <vector> template<typename T> class Vec : std::vector<T> { private: using std::vector<T>::vector; // 可行,即使设为私有。原因是什么? public: using std::vector<T>::operator[]; // 必须设为公有 }; int main(){ Vec<int> vec = {2, 2}; auto test = vec[1]; }
咱们分两个部分来拆解这个差异:
一、基类构造函数的using声明设为私有仍可构造的原因
C++标准对继承基类构造函数的using声明有特殊的访问性规则:当你通过using Base::Base;将基类构造函数引入派生类时,这些继承来的构造函数的可访问性直接继承自基类中对应构造函数的访问级别,而不是由派生类中using声明所在的访问控制块(比如private)来决定。
具体到你的代码:
std::vector<T>的构造函数(包括初始化列表构造函数)本身是public的;- 尽管你把
using std::vector<T>::vector;放在了private块里,但继承来的构造函数依然保持基类的public访问性; - 所以在
main里可以直接用Vec<int> vec = {2, 2};来构造对象,编译器会调用继承自std::vector的初始化列表构造函数,这个调用是完全合法的。
另外补充一点:哪怕你的Vec是私有继承std::vector,这个规则依然适用——因为继承构造函数的访问性只看基类构造函数本身的权限,和继承方式(公有/私有/保护)无关。
二、operator[]的using声明必须设为公有原因
对于基类普通成员函数(包括运算符重载)的using声明,规则就不一样了:这类using声明的作用是把基类的成员函数引入派生类的作用域,而该成员函数在派生类中的可访问性由using声明所在的访问控制块决定。
回到你的代码:
Vec是私有继承std::vector<T>,这意味着std::vector的所有public成员在Vec外部默认是不可访问的;- 如果你把
using std::vector<T>::operator[];放在private或protected块里,那么这个运算符重载函数在Vec外部就无法被访问,main里的vec[1]会触发编译错误; - 只有把这个using声明放在
public块里,才能让外部代码合法调用这个运算符。
内容的提问来源于stack exchange,提问作者wally
相关产品推荐
相关产品推荐

