C++ 为什么一定要把一个论点交给const呢?

C++ 为什么一定要把一个论点交给const呢?,c++,visual-studio,constants,C++,Visual Studio,Constants,我的理解是,参数声明中的常量表示所声明的函数不会更改常量值。那么,为什么这会对调用者传递的参数的稳定性提出要求呢 定义代码: void Func(const Foo**); main() { Foo* fooPtr; Func(&fooPtr); } Visual Studio 2012编译器产量: > error C2664: 'Func' : cannot convert parameter 1 from 'Foo**' to 'const Foo**' >

我的理解是,参数声明中的常量表示所声明的函数不会更改常量值。那么,为什么这会对调用者传递的参数的稳定性提出要求呢

定义代码:

void Func(const Foo**);

main()
{
  Foo* fooPtr;
  Func(&fooPtr);
}
Visual Studio 2012编译器产量:

> error C2664: 'Func' : cannot convert parameter 1 from 'Foo**' to 'const Foo**'
> Conversion loses qualifiers
但以下工作:

main()
{
  Foo* fooPtr;
  Func(const_cast<const Foo**>(&fooPtr));
}

基本理论是什么?

如果允许转换,则可以使用转换规避常量正确性:

const Foo const_foo;

void evil(const Foo** p) {
    *p = &const_foo; // *p is 'const Foo*', so this assignment is allowed
}

int main() {
    Foo* p;
    evil(&p);     // modifies p to point to const_foo
    p->modify();  // BOOM! Modifying a constant object
}

您可以转换为常量Foo*const*;这不允许您将Foo*更改为指向任何其他对象,因此不能破坏常量的正确性。这比使用诡计多端的演员阵容并期待最好的结果要好;尽管您应该问问自己,为什么不简单地按值传递指针,但如果您不想更改它。

如果允许转换,则可以使用它来规避常量正确性:

const Foo const_foo;

void evil(const Foo** p) {
    *p = &const_foo; // *p is 'const Foo*', so this assignment is allowed
}

int main() {
    Foo* p;
    evil(&p);     // modifies p to point to const_foo
    p->modify();  // BOOM! Modifying a constant object
}

您可以转换为常量Foo*const*;这不允许您将Foo*更改为指向任何其他对象,因此不能破坏常量的正确性。这比使用诡计多端的演员阵容并期待最好的结果要好;尽管您应该问问自己,如果您不想更改指针,为什么不简单地按值传递指针。

如果Func&fooPtr确实修改了fooPtr,而保留*fooPtr不变,那么Func应该有两个版本,一个根据另一个定义:

void Func(const Foo**);
void Func(Foo** fooHndl)
{
  Func(const_cast<const Foo**>(fooHndl));
}

这允许使用句柄**调用Func以访问常量或非常量对象。

如果Func&fooPtr确实修改了fooPtr,而*fooPtr保持不变,则应该有两个版本的Func,一个版本根据另一个版本定义:

void Func(const Foo**);
void Func(Foo** fooHndl)
{
  Func(const_cast<const Foo**>(fooHndl));
}

这允许使用句柄**调用Func,调用常量或非常量对象。

不要这样做。将参数设置为适当的const Foo*const*@chris:如果不想更改调用方的指针,请按值传递const Foo*。如果这样做,那么参数类型就可以了,尽管const Foo*&可能更为惯用;调用它的参数的类型是错误的。@MikeSeymour,没错,只是const Foo*const*是&fooPtr可以自动转换为的常量版本。我同意这可能不是最好的类型选择。不要这样做。将参数设置为适当的const Foo*const*@chris:如果不想更改调用方的指针,请按值传递const Foo*。如果这样做,那么参数类型就可以了,尽管const Foo*&可能更为惯用;调用它的参数的类型是错误的。@MikeSeymour,没错,只是const Foo*const*是&fooPtr可以自动转换为的常量版本。我同意这可能不是最好的类型选择。很好的答案和很好的例子。我想你可以把你对克里斯的评论移到答案的末尾来改进你的答案,因为它处理的是我的直接案例。特别是,我的Foo*fooPtr实际上是非常量的,我确实希望修改Func中的指针,同时Func承诺不修改对象本身。你的例子清楚地说明了为什么Func不可能做出这样的承诺。在我的应用程序中,fooPtr指向列表的尾部,Func向它附加了一个特定的项,要求更新fooPtr。我想最好的办法是从Func的参数中删除承诺。。。除非你或其他人有其他建议。。。谢谢你!。。。虽然从Func中删除const承诺意味着在const fooPtr上调用Func将需要在另一个方向上强制转换const_。。。显然,为了避免const_强制转换,必须存在两个版本的Func!如果Func确实修改了fooPtr,那么应该有两个版本的Func,一个是根据另一个定义的:很好的答案和很好的示例。我想你可以把你对克里斯的评论移到答案的末尾来改进你的答案,因为它处理的是我的直接案例。特别是,我的Foo*fooPtr实际上是非常量的,我确实希望修改Func中的指针,同时Func承诺不修改对象本身。你的例子清楚地说明了为什么Func不可能做出这样的承诺。在我的应用程序中,fooPtr指向列表的尾部,Func向它附加了一个特定的项,要求更新fooPtr。我想最好的办法是从Func的参数中删除承诺。。。除非你或其他人有其他建议。。。谢谢你!。。。虽然从Func中删除const承诺意味着在const fooPtr上调用Func将需要在另一个方向上强制转换const_。。。显然,为了避免const_强制转换,必须存在两个版本的Func!如果Func确实修改了fooPtr,那么Func应该有两个版本,一个是根据另一个定义的: