【问题标题】:C++ const questionC++ 常量问题
【发布时间】:2010-09-21 03:46:46
【问题描述】:

如果我这样做:

// 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

代码将无法编译。

发生了什么事? 我正在使用 gcc 4.1.x

【问题讨论】:

  • 您的意思是在第二个示例中将 const 放在 * 的另一侧吗?有些人通过解释其含义的差异来回答,而其他人则通过解释 const 是在 cpp 还是 h 文件中的差异来回答。
  • 您应该为您的问题选择一个答案,或者如果它不是您要寻找的答案,请更新。

标签: c++ gcc constants


【解决方案1】:

首先,您已向编译器(而非该类的其他用户)承诺您不会编辑该变量。

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

我还应该注意,两者之间有明显的区别

bar* const variable

const bar* variable

const bar* const variable

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

要对所述问题进行更多说明,您始终可以承诺 MORE const 多于 less。给定一个类:

class Foo {
    void func1 (int x);
    void func2 (int *x);
}

您可以编译以下实现:

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

或:

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

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

【讨论】:

  • 我不认为你的理论成立:1)如果你声明“int*”并实现“const int*”,就像你的例子一样,它不会编译。 2)如果按值传递,可以声明const而不用const实现。传值时没有意义。
  • 是的。我同意你错了。无效 f(int const*);不同于 void f(int *);我想你想写 void f(int * const);与 void f(int *); 具有相同的签名;你应该改变你的例子,因为它可能会让初学者感到困惑。
【解决方案2】:

请参阅this questionthis questionthis question

基本上,const 只表示函数不会修改指针的值。指针内容不是const,和header的签名一样。

【讨论】:

    【解决方案3】:

    第一个例子中的 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 是按值传递的,所以常量无关紧要。

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

    【讨论】:

      【解决方案4】:

      所以第二个常量在:

      void Foo::foo(const bar* const);
      

      不是方法签名的一部分吗?

      【讨论】:

      • 你在 .h 文件中声明一个方法,你在 .cpp 中定义它。声明中的所有内容都是签名的一部分(两个 const),看起来在定义中您可以更仔细地细化参数类型,只要该定义不破坏声明的语义。
      • @mamin:正确。例如,如果您声明(但未定义)一个函数“void foo(const int* const a)”,然后调用它,请查看您得到的链接器错误。 GCC 报告缺少的签名是“foo(int const*)”。
      • 简单:如果您添加/删除 const 它不会成为签名的一部分。所以 void foo(intconst);和 void foo(int);确实有相同的签名。但是 void foo(int const*);和 void foo(int*);确实有不同的签名:参数类型没有添加 const,而是指向的类型。
      【解决方案5】:

      使用变量类型而不是指针,这更容易理解。例如,您可以有以下函数声明:

      void foo( int i );
      

      定义可能如下所示:

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

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

      【讨论】:

      • 我不明白 SO 用户的投票方式。上面+15投票的顶部是一个答案,最后有一个错误的陈述并且不想修复它(ppl在3个月前告诉他),而在-1这个答案是好的并且解释得更好(恕我直言)。为了公平起见 +1。
      【解决方案6】:

      它可能不太关心void Foo::foo(bar* const pBar),因为你如何对待指针本身(const 与否)在例程之外一点都不重要。 C 规则说,对 pBar 的任何更改都不会在 foo 之外传播。

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

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 我认为您在最后一句中的意思是“您不会修改 bar* 指向的栏”。 “更改 bar* 指向的内容”可能被理解为“给 bar* 一个新值”,这在第二个示例中当然没问题。
        • 感谢您,已修复。代词是清晰的祸根。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-27
        • 2011-02-12
        • 2013-02-25
        • 2011-07-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多