我是一名新手C ++程序员,但我认为我对C ++知之甚多,直到今天我在工作中遇到这样的代码并且无法理解它是如何工作的。
class Object
{
};
template <
class PropObject,
class PropType,
PropType PropObject::* Prop
>
class PropReader
{
public:
void print(Object& o)
{
PropObject& po = static_cast<PropObject &>(o);
PropType& t = po.*Prop;
cout << t << "\n";
}
};
class Student : public Object
{
public:
int age;
int grade;
};
int _tmain(int argc, _TCHAR* argv[])
{
Student s;
s.age = 10;
s.grade = 5;
PropReader<Student, int, &Student::age> r;
PropReader<Student, int, &Student::grade> r2;
r.print(s);
r2.print(s);
}
我认为我在高层次上有所了解。但是模板声明中的这个特殊PropType PropObject::* Prop
困扰着我。这是什么意思?我正在寻找C ++专家的解释。我想了解它,以便我可以更好地使用它。它看起来非常有用。
答案 0 :(得分:18)
C ++模板以将类型作为参数而众所周知,但它们也可以通过其他类型的数据进行参数化。例如,您可以在整数上模拟一个类,如下所示:
template <typename T, unsigned int N> class Array {
private:
T array[N];
public:
/* ... */
};
模板也可以通过指针进行参数化,只要指针符合某些条件(例如,它必须计算到可以在编译时确定的某个地址)。例如,这是完全合法的:
template <int* Pointer> class ThisIsLegal {
public:
void doSomething() {
*Pointer = 137;
}
};
在您的代码中,模板通过指向类成员的参数化进行参数化。指向类成员的指针类似于指针,因为它间接引用某个对象。但是,它不是指向一个对象,而是指向一个类中的一个字段。我们的想法是,您可以取消引用相对于某个对象的指向类成员的指针,以便从该类中选择该字段。这是一个指向类成员的简单示例:
struct MyStruct {
int x, y;
};
int main() {
MyStruct ms;
ms.x = 137;
ms.y = 42;
int MyStruct::* ptr; // Declare a pointer to a class member.
ptr = &MyStruct::x; // Now points to the field 'x'
ms.*ptr = 0; // Set the 'x' field of ms to be zero.
}
请注意,声明指向类成员的指针的语法是
Type ContainingClass::* pointerName;
因此,在上面的代码中,int MyStruct::* ptr
表示“指向int
类内MyStruct
的指针。
在您发布的代码中,模板声明如下所示:
template <
class PropObject,
class PropType,
PropType PropObject::* Prop
>
class PropReader
让我们看看这意味着什么。将要读取其属性的前两个模板参数对象,以及该属性的类型PropType
。“模板的最后一个参数是一个名为Prop
的指向类的成员,在PropObject
类型的字段PropType
内的点。例如,您可以使用MyStruct
实例化此模板,如下所示:
PropReader<MyStruct, int, &MyStruct::x> myPropReader;
现在,让我们看看其余代码的作用。这个类模板的主体在这里重印:
void print(Object& o)
{
PropObject& po = static_cast<PropObject &>(o);
PropType& t = po.*Prop;
cout << t << "\n";
}
其中一些可以很容易地阅读。此函数的参数是对Object
o
的引用,最后一行打印出一些字段。这两行很棘手:
PropObject& po = static_cast<PropObject &>(o);
PropType& t = po.*Prop;
这第一行是一个类型转换,上面写着“试图将参数o
强制转换为PropObject
类型的引用。我猜,这个想法是Object
是一些许多不同对象的基类。函数的参数只是一个普通的Object
,这个演员试图将它转换为适当类型的东西(回想一下PropObject
是模板参数说的该对象的类型是什么)。因为它使用static_cast
,如果未定义转换(例如,您尝试在int
或vector<string>
上实例化模板),代码将无法编译。否则,代码信任转换是安全的,然后获取类型PropObject
的引用到参数引用的内容。
最后,最后一行是
PropType& t = po.*Prop;
这使用前面提到的指向类成员的解引用语法来说“选择Prop
指向的字段(模板参数),然后存储名为t
的引用
简而言之,就是模板
print
函数,给定对象尝试打印该字段。呼!那太棘手了!希望这有帮助!
答案 1 :(得分:4)
C或C ++中的声明通常最好从右到左阅读:
PropType PropObject::* Prop
~~~~ The Prop template parameter
~~~ is a pointer to a member
~~~~~~~~~~ of a PropObject
~~~~~~~~ where that member has type PropType
这可以在实例化中看到:
PropReader<Student, int, &Student::age> r;
此处第三个模板参数是指向Student
类成员的指针,其类型为int
。
答案 2 :(得分:3)
PropObject::*
是指向成员的指针(在本例中为数据成员)。它基本上是指向(非静态)成员的指针(在代码的情况下为Student::age
和Student::grade
)。
要使用它,您必须指定该函数将使用的this
对象。这是通过使用.*
或->*
运算符完成的;在这种情况下,PropType& t = po.*Prop;
行处理,其中po
用作成员的this
对象。
答案 3 :(得分:1)
这是将指针作为参数传递给成员的语法。特别是在这种情况下,可以传入age
和grade
成员。虽然模板args指定Student
类,但它是成员,成员属性为{{1 }}
如果您向学生添加了字符串名称,则PropReader声明可能如下所示:
int
答案 4 :(得分:0)
但是这个特定的PropType PropObject :: * Prop在模板中 宣言困扰我。这是什么意思?
PropType PropObject::* Prop
这定义了指向类的成员变量的指针,在这种特殊情况下,该类是PropObject,变量类型是PropType。