我们用T来表示类型,这里的类型可以是系统内置类型,也可以是用户自定义类型。
首先要明确一点:将T** 类型的指针赋给 const T**类型的指针是不合法的,即使你非要强制转换来赋值,那样做也是十分危险的。
大家都知道,C++允许我们将T*类型的指针赋值给const T*类型的指针,这是因为const T*类型的指针具有底层const属性,它可以保证通过它,你不能修改它指向的内容。
但是,到指针升级为二维指针,情况就变了。虽然,从直觉上来讲,应该可以赋值。但在这里,直觉是错误的。
首先,我们先弄清两个概念:
char** 表示: pointer to pointer to char.
const char** 表示: pointer to pointer to const char.
const T c;
const T* p;
const T** myPtr;
myPtr = &p;
p = &c;
对于上述代码,在内存中,指针是这样分布的:
红色部分正是薄弱环节处。这是由const T** myPtr; 这样的定义引起的。对于myPtr来说,在语法层面,指针(*myPtr)是可以指向const T变量的。这正是薄弱环节所在。
看下面这个程序:
const char c = 'c';
char* p;
const char** myPtr = &p; // #1: not allowed
*myPtr = &c;
*p = 'C'; // #2: modifies a const object
通过上图我们也可以看到,因为(*myPtr)可以指向const char c,如果允许T** 赋值给 const T**,即允许myPtr指向普通指针p,则之后我们让指针p以(*myPtr)的名义再指向const变量c,那么我们就可以通过指针p来修改 c 的值了。
所以不允许T** 赋值给 const T**,也就是说,不允许T** 类型的指针隐式转换成 const T**。
T
**
→ const T**
要被禁止,是因为这样做可能会在无意中改变一个const常量的值。
那怎么解决T** 向 const T**赋值的问题呢?
我们再来看一个例子:
class Foo { /* ... */ };
void f(const Foo** p);
void g(const Foo* const* p);
int main()
{
Foo** p = /*...*/;
// ...
f(p); // ERROR: it's illegal and immoral to convert Foo** to const Foo**
g(p); // Okay: it's legal and moral to convert Foo** to const Foo* const*
// ...
}
看过上面的例子,我们就可以很清楚怎么解决这个问题了。
即将const char** myPtr; 修改为 const char* const* myPtr;
当然,对于char** 类型的指针,可以隐式转换成 char * const * ,也可以转换成const char * const * .