为何联合体中继承的结构体成员不可访问?如何使其可访问?
问题原因分析
你遇到的问题核心在于C++对匿名结构体成员和匿名基类的处理规则差异:
- 你定义的
struct { int one; };和struct { int two; };属于匿名结构体成员——这类成员的所有成员会被编译器直接注入到外围union的作用域中,因此你能直接通过a.one、a.two访问它们(这是主流编译器都支持的实用扩展特性)。 - 但
struct : s {};是一个匿名基类(union继承了这个无名结构体,而该结构体又继承了s)。根据C++标准,基类的成员属于基类子对象,不会自动被提升到外围类/union的作用域中,所以编译器不会把s的three成员视为alias的直接成员,自然就会报“找不到成员”的错误。
解决方法
下面提供几种能实现你“为s成员提供直接别名”需求的方案:
方案1:用using声明引入基类成员
在union内部通过using关键字,显式把基类s的成员引入到alias的作用域中,这样就能直接访问three了:
struct s { int three; }; union alias { struct { int one; }; struct { int two; }; struct : s {}; using s::three; // 显式将基类成员纳入union作用域 }; int main() { alias a; a.one = 1; a.two = 2; a.three = 3; // 现在可以正常访问 return 0; }
方案2:将s作为匿名成员而非基类
放弃继承写法,直接把s作为union的匿名成员,这样它的成员会像one、two一样被注入到union作用域,写法更简洁:
struct s { int three; }; union alias { struct { int one; }; struct { int two; }; s; // 匿名的s类型成员,其成员直接成为union的成员 }; int main() { alias a; a.one = 1; a.two = 2; a.three = 3; // 正常访问 return 0; }
这个方案最贴合你原本想给s成员起直接别名的需求。
方案3:给继承的结构体命名(不推荐)
如果只是为了能访问成员,也可以给继承s的结构体起个名字,但这样就失去了“直接别名”的便利性,仅作参考:
struct s { int three; }; union alias { struct { int one; }; struct { int two; }; struct wrapped_s : s {}; // 给继承结构体命名 }; int main() { alias a; a.one = 1; a.two = 2; a.wrapped_s.three = 3; // 需要通过命名结构体访问 return 0; }
内容的提问来源于stack exchange,提问作者Oleksandr
相关产品推荐
相关产品推荐

