C++ C++;常数问题

C++ C++;常数问题,c++,gcc,constants,C++,Gcc,Constants,如果我这样做: // In header class Foo { void foo(bar*); }; // In cpp void Foo::foo(bar* const pBar) { //Stuff } 编译器不会抱怨Foo::Foo的签名不匹配。但是,如果我有: void foo(const bar*); //In header void Foo::foo(bar*) {} //In cpp 代码将无法编译 发生了什么事? 首先,我使用的是GCC4.1.x,您已经向编译器承诺过,

如果我这样做:

// In header 
class Foo {
void foo(bar*);
};

// In cpp
void Foo::foo(bar* const pBar) {
//Stuff
}
编译器不会抱怨Foo::Foo的签名不匹配。但是,如果我有:

void foo(const bar*); //In header
void Foo::foo(bar*) {} //In cpp
代码将无法编译

发生了什么事?
首先,我使用的是GCC4.1.x,您已经向编译器承诺过,但没有向类的其他用户承诺您不会编辑该变量

在第二个示例中,您已经向该类的其他用户承诺您不会编辑他们的变量,但未能遵守该承诺

我还应该指出,两者之间有着明显的区别

bar* const variable

在第一种形式中,指针永远不会更改,但您可以编辑指向的对象。在第二种形式中,可以编辑指针(将指针指向另一个对象),但不能编辑指针指向的变量。在最终形式中,您既不会编辑指针,也不会编辑指针指向的对象

为了对所述问题进行更多的澄清,你可以承诺更多的常量而不是更少。给定一个类:

class Foo {
    void func1 (int x);
    void func2 (int *x);
}
您可以编译以下实现:

Foo::func1(const int x) {}
Foo::func2(const int *x) {}
或:


没有任何问题。您已经告诉您的用户您可能会编辑他们的变量。在您的实现中,您已经告诉编译器这个特定的实现将不会编辑这些变量,即使编译器告诉用户您可能会编辑这些变量。您没有违背对用户的承诺,因此代码可以编译。

在前者中,
常量不影响界面,只影响实现。您对编译器说,“我不会在这个函数中更改
bar*
的值”。您仍然可以更改指针指向的内容。在后者中,您告诉编译器(和所有调用者)您将不会更改
bar*
指向的
bar
结构。

请参阅,和


基本上,const只意味着函数不会修改指针的值。指针内容不是常量,与标头的签名相同。

因此,中的第二个常量:

void Foo::foo(const bar* const);
不是方法签名的一部分吗?

第一个示例中的const关键字没有意义。您是说您不打算更改指针。但是,指针是按值传递的,所以不管您是否更改它;这不会影响呼叫方。同样,您也可以这样做:

// In header 
class Foo {
void foo( int b );
};

// In cpp
void Foo::foo( const int b ) {
//Stuff
}
您甚至可以这样做:

// In header 
class Foo {
void foo( const int b );
};

// In cpp
void Foo::foo( int b ) {
//Stuff
}
因为int是通过值传递的,所以常量并不重要


在第二个示例中,您说您的函数使用指向一种类型的指针,但随后将其实现为使用指向另一种类型的指针,因此它失败。

使用指针以外的变量类型更容易理解这一点。例如,可以使用以下函数声明:

void foo( int i );
定义可以如下所示:

void foo( const int i ) { ... }

变量“i”在定义端是否为常量是一个实现细节。它对该函数的客户端没有影响。

它可能不太关心
void Foo::Foo(bar*const pBar)
,因为如何处理指针本身(const或not)在例程之外一点都不重要。C规则规定,无论哪种方式,对pBar的更改都不会在foo之外进行


但是,如果是
(const bar*pBar)
,则会产生不同,因为这意味着编译器不允许调用者传入指向非常量对象的指针。

在.h文件中声明方法,在.cpp中定义方法。声明中的所有内容都是签名的一部分(两个常量),似乎在定义中可以更精确地细化参数类型,只要该定义不破坏声明的语义。@mamin:Correct。例如,如果您声明(但未定义)一个函数“void foo(const int*const a)”,然后调用它,请查看您得到的链接器错误。GCC报告缺少的签名是“foo(int const*)”。很简单:如果添加/删除const,它将不会成为签名的一部分。so void foo(intconst);及void foo(int);;确实有相同的签名。但是void foo(int const*);及void foo(int);;确实有不同的签名:没有常量添加到参数类型,而是添加到指向的类型。在第二个示例中,您的意思是将常量放在*的另一侧吗?有些人通过解释其含义上的差异来回答问题,而另一些人则通过解释常量是在cpp文件还是在h文件中的差异来回答问题。如果不是你想要的答案,你应该选择一个答案或更新。我认为你的理论不成立:1)如果你声明“int*”并实现“const int*”,如您的示例所示,它不会编译。2) 如果按值传递,则可以声明const而不使用const实现。当您传递值时,它没有意义。是。我同意你错了。空f(整数常数*);与void f(int*)不同;我想你想写void f(int*const);具有与void f(int*)相同的签名;你应该改变你的例子,因为它可能会让初学者感到困惑。我认为你在最后一句话中的意思是“你不会修改条*指向的条”。“更改条*指向的内容”可能意味着“给条*一个新的值”,这在第二个示例中当然是好的。谢谢,修正了。代词是清晰度的祸根。我不明白用户怎么投票。上面的top Vote和+15是一个在结尾有错误陈述的答案,不想纠正它(ppl在3个月前告诉他),而at-1是这个答案,这是正确的,解释得更好(IMHO)。为了公平起见,做+1。
// In header 
class Foo {
void foo( const int b );
};

// In cpp
void Foo::foo( int b ) {
//Stuff
}
void foo( int i );
void foo( const int i ) { ... }