我知道这个问题有点老了,但是我开发了一种方法,没有任何答案使用它,我想分享一下。
首先,在C++中,我们通常不鼓励直接访问成员变量,而是鼓励提供设置器/获取器来帮助实现信息隐藏。
其次,虽然C++在消除宏的使用方面已经取得了很大进展,但宏仍然可以完成许多使用模板和类难以实现(或几乎不可能)的事情。
以下使用宏为类中的容器成员字段创建类型化的设置器和获取器:
#define Bit(n) (1 << (n))
#define BitMask(n) (Bit(n) - 1)
#define BitRange(n,m) (BitMask(n) ^ BitMask(m))
#define namedBitField(name, container, start, end, EnumType) \
EnumType name() const \
{return \
(EnumType) \
((container & BitRange(start,end)) \
>> start); \
}; \
void name(EnumType v) {container |= (v << start);}; \
class myTest
{
public:
enum vSet1
{
a = 1,
b = 2,
};
private:
unsigned long holder;
public:
myTest() {};
namedBitField(set1, holder, 0, 3, vSet1);
namedBitField(set2, holder, 4, 5, vSet1);
};
myTest mt;
namedBitField() 宏接受 getter/setter 对的 name,目标container -- 在此示例中为 holder,位域的 start/end,以及用于位域值的 EnumType。
如果我现在在上面的示例中使用名为 set1() 和 set2() 的 setter/getter 对,并尝试传递 POD(plain-old-data)数字,则会收到编译器的警告。
mt.set1(22); // compiler warns here.
mt.set1();
mt.set2(myTest::vSet1::a); // no warnings.
mt.set2();
不,它不是一个“类型化位域”,但它是次优选择。
不,使用定义结构中的位域并不像这种方式那么容易,但是通过setter/getter您可以获得强类型。
现在,您可以在结构体中定义位域,将它们设置为私有,并通过setter/getter访问它们,但这样会导致有关位的位置的信息与用于该信息的setter/getter分离。正如上面的几位回答者所指出的那样,每个C++编译器都可以将位放置在任何位置,因此如果不查看生成的汇编代码或在硬件上进行测试(如果你很勇敢),你不能确定事情是否按照你想要的方式发生。
namedBitField()创建的setter/getter以一定顺序操纵位,并保证container内的位顺序,因此您现在可以跨平台使用代码来访问I/O寄存器。
注意:在我的示例中,我将“名称”用作setter和getter,编译器根据使用情况自动排序。有些人可能更喜欢“get_name”和“set_name”。您的情况可能会有所不同。
由于getter/setter是公共的,只要你迭代的所有东西都派生自同一个基类,你现在可以遍历向量中的项目(如上所述),并获得用于迭代中使用的值的类型安全的获取/设置。
doSomething
的效果在函数外部不可见。通过引用调用是为了确保结果在调用者的向量中可见。 - Bart van Ingen Schenau