我正在尝试了解“指向成员的指针”的工作原理,但并不是所有事情对我来说都是显而易见的。
这是一个示例类:
class T
{
public:
int a;
int b[10];
void fun(){}
};
以下代码说明了问题并包含一些问题:
void fun(){};
void main()
{
T obj;
int local;
int arr[10];
int arrArr[10][10];
int *p = &local; // "standard" pointer
int T::*p = &T::a; // "pointer to member" + "T::" , that is clear
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
int *pA = arr; // ok
int T::*pA = T::b; // error
int (T::*pA)[10] = T::b; // error
int (T::*pA)[10] = &T::b; //works;
//1. Why "&" is needed for "T::b" ? For "standard" pointer an array name is the representation of the
// address of the first element of the array.
//2. Why "&" is not needed for the pointer to member function ? For "standard" pointer a function name
// is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
// That's rule works there.
//3. Why the above pointer declaration looks like the following pointer declaration ?:
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
system("pause");
}
我认为最简单的事情是暂时忘记类成员,然后回顾指针和衰减。
int local;
int array[10];
int *p = &local; // "standard" pointer to int
人们倾向于说“衰减的指针”与指向数组的指针相同。但是arr
和之间有一个重要的区别&arr
。前者不会衰退为后者
int (*p_array_standard)[10] = &arr;
如果这样做&arr
,您将获得一个指向10整数数组的指针。这与指向9整数数组的指针不同。它与指向int的指针不同。sizeof(*p_array_standard) == 10 * sizeof(int)
。
如果你想有一个指针的第一个元素,即一个指针int
,用sizeof(*p) == sizeof(int))
,那么你可以这样做:
int *p_standard = &(arr[0);
到目前为止,所有内容都基于标准/显式指针。
在C中一个特殊的规则,它允许您更换&(arr[0])
同arr
。您可以int*
用&(arr[0])
或用初始化一个arr
。但是,如果您实际上想要一个指向数组的指针,则必须int (*p_array_standard)[10] = &arr;
我认为这种衰变几乎可以被视为一种语法糖。衰减不会改变任何现有代码的含义。它只是允许否则将是非法的代码变为合法。
int *p = arr; // assigning a pointer with an array. Why should that work?
// It works, but only because of a special dispensation.
当数组衰减时,它衰减为指向单个元素的指针int [10]
-> int*
。它不会衰减到指向该数组的指针int (*p)[10]
。
现在,我们可以从您的问题来看这一行:
int (T::*pA3)[10] = T::b; // error
同样,班级成员与理解为什么失败无关。左侧的类型是整数的指针,而不是整数的指针。因此,正如我们之前所说,衰减不相关,您需要&
获取指向整数数组的指针类型。
一个更好的问题是问为什么这不起作用(更新:我现在看到您的问题中确实有这个问题。)
int T::*pA3 = T::b;
右侧看起来像一个数组,而左侧是指向单个元素的指针int *
,因此您可以合理地问:为什么衰减在这里不起作用?
要理解为什么衰减很难在这里,让我们的“撤消”语法糖,并更换T::b
有&(T::b[0])
。
int T::*pA3 = &(T::b[0]);
我认为这是您感兴趣的问题。为了关注实际问题,我们已经删除了衰减问题。该行适用于非成员对象,为什么不适用于成员对象?
简单的答案是该标准不需要它。指针衰减是一种语法糖,他们只是没有指定它在这种情况下必须起作用。
指向成员的指针基本上比其他指针要容易。它们必须直接指向对象中出现的“原始”实体。(对不起,我的意思是它应该(通过编码类的开头和该成员的位置之间的偏移量来间接地引用。但是我不太擅长对此进行解释。)它们不能指向子对象,例如数组的第一个元素,或者实际上是数组的第二个元素。
问:现在我有一个自己的问题。可以将指针衰减扩展到这样的成员数组上吗?我认为这是有道理的。 我不是唯一想到这一点的人!有关更多信息,请参见此讨论。这是可能的,我想没有什么可以阻止编译器将其实现为扩展。子对象(包括数组成员)与类的开头有固定的偏移量,因此这很合逻辑。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句