【问题标题】:How to convert this VC++ 6 code to VC++ 2008?如何将此 VC++ 6 代码转换为 VC++ 2008?
【发布时间】:2009-04-11 17:06:23
【问题描述】:

请原谅我的 C++ 生锈得令人难以置信。但我正在尝试获取一些旧代码并在 Visual C++ 2008 下重新编译它。它最初是为 Visual C++ 6.0 编写的

我得到的错误是这样的:

错误 C4430:缺少类型说明符 - 假定为 int。注意:C++ 不支持 default-int

好的,看起来很简单。但后来我看看有问题的代码行:

operator=(int i) {SetAsInt(i);};

它似乎声明了类型。那我错过了什么?

跟进:

我接受了 Micheals 的建议并添加了函数(类)的返回类型,并在每个末尾添加了 return this;。然后我遇到了这个:

operator=(const CString& str);

没有定义函数体...这到底是什么意思?

【问题讨论】:

  • 请注意,返回对象的引用而不是对象的指针可能应该是return *this;。或者,您可以通过声明返回 void 的方法,正如 Neil Butterworth 所建议的那样,您可能无法获得分配链支持(通常可以忽略不计)。

标签: c++ visual-studio visual-studio-2008 visual-c++


【解决方案1】:

您需要让operator=() 方法返回一些内容(如果诊断不是错误,它将假定为 int,因为错误消息有些令人困惑)。

通常它是对运算符正在处理的对象的引用,因此可以像在正常的赋值表达式中一样链接赋值。比如:

// where T is the class for this operator= implementation

T& operator=( int i) {
     // ...
    return *this;
}

【讨论】:

  • 最好使用 const,即:T const &operator=(int i)
  • 它可以返回一个 const&,但通常不会。 operator=() 不是一个 const 方法(除非你正在做一些真正的事情),所以它没有什么理由返回一个 const&。并且返回一个 const& 会阻止经典(尽管不一定广泛使用)a = b = c; 链接。
  • “返回一个 const& 可以防止经典的(虽然不一定广泛使用)a = b = c; 链接。”不完全是,复制构造函数是从 const 引用创建的,因此赋值运算符具有签名 T const &operator=(T const &) 并且它以上述方式工作。
  • @Artyom:关于我返回 const& 防止赋值链接的错误,你是对的(虽然不是因为复制构造函数 - 这是因为 = 的关联性意味着 const& 结果是赋值的操作数,而不是目标)。
  • @Artyom:我看到的关于 operator=() 的通常建议是返回一个 T& - 在这次交换之后,我将开始考虑使用 T const& 除非我能想到一个好的const 应该被忽略的原因 - 或者其他人是否可以教育我。感谢您说服我重新考虑这一点。
【解决方案2】:

正如 michael 所说,operator= 需要一个返回类型,但这种类型可以是 void:

class A {
   ...  
   void operator = ( int i ) {
      SetAsInt(i);
   }
};

虽然这意味着您将无法“菊花链式”分配。

关于后续,可能是说禁止给班级分配:

class B {
    private:
        void operator =( const B & );    
};

将分配操作(通常是复制ctor)设为私有然后不实现它们意味着不可能分配(或复制)类实例,这是大多数面向业务的类的理想行为。

【讨论】:

    【解决方案3】:

    对于你的第二个问题,声明很可能被用来防止复制对象。

    来自the C++ Reference Guide by Danny Kalev

    问题:我该如何预防 对象复制?

    答案:声明复制构造函数 并且赋值运算符是私有的 成员,而不定义它们。任何 涉及直接或 该类的间接复制将 导致编译错误。这 技术并不完全是 优雅,但在当代 C++ 中 没有其他方法可以阻止复制 便宜。

    【讨论】:

    • 好的,这对它有所启发。在我的 C++ 大学时代,他们从未提到过这一点。
    【解决方案4】:

    关于您的编辑: 它只是意味着该函数已被声明,但未定义。编译器知道它存在,所以调用它是合法的。但它会产生链接器错误,除非编译器实际上能够在某处找到正文。

    通常,你在头文件中定义函数,然后在 .cpp 文件中,你有类似的东西

    // Assuming the class it is a member of is called Foo
    Foo& Foo::operator=(const CString& str) {
     ...
    }
    

    这里唯一需要注意的是 Foo:: 前缀。因为这个定义在类定义本身之外,所以我们必须使用这个前缀来指定我们正在定义的 operator= 属于 Foo 类。

    【讨论】:

    • 好的,我找到了函数体。虽然我从不明白为什么 C++ 有这种奇怪的想法,即在一个地方声明,在另一个地方定义。
    • 抓得好,贾夫。我从来没有想过要讨论这个解释,因为它是大多数 C++ 方法的定义方式。但是,我同意 Neil 的观点,声明/定义(如 Java/C#)只有一个位置更直观。
    • 因为这样您可以#include 仅包含声明的文件,并且您可以调用该函数,而无需编译器再次解析整个函数体。在 70 年代,当设计 C 时,这是一种加快编译时间的简单方法。
    • 30-40 年前,编译器无法证明像 Java/C# 编译器那样将整个文件保存在内存中的成本是合理的。它必须按顺序扫描文件,所以事情必须保持简单。今天,它是一种笨拙、容易出错且效率低下的机制。但在当时是有道理的。 ;)
    【解决方案5】:

    返回 ANYTHING 但 lval 通常是错误的,仅在非常特殊的情况下使用

    返回一个 const 引用肯定会排除赋值链 (a=(b=c)),而运算符的部分意义在于使类的行为类似于内置类型

    【讨论】:

      【解决方案6】:

      嗯,这是一个赋值运算符。它有助于定义如何将其他对象(相同类型和其他类型)分配给定义它的类的实例。

      正确的语法是(假设你的类叫做'Object'):

      const Object& operator=(const Object& other)
      {
        // copy members, one at a time.
        this->member1 = other.member1;
        return *this;
      }
      

      注意返回类型是常量。这是为了避免语义不正确、语法正确的语句,例如:

      Object A, B, C;
      
      (A = B) = C;
      

      如果将返回类型定义为常量,上面的代码将无法编译(足够合理,因为它真的很乱),而省略 const 将允许这样糟糕的代码编译,当然有人会拉扯他们的头发尝试找出问题所在。

      附:您可能需要考虑一下:如果您从返回类型中省略 const 并执行 (A = B) = C; 会发生什么?代码?

      【讨论】:

        【解决方案7】:

        关于后续问题,在这种情况下,返回类型可以是任何东西。但是,由于大多数赋值运算符都返回对声明它们的类的引用,因此最好只返回该引用,以免使读者感到困惑。

        CString& operator=(const CString& str);
        

        大概,这个函数是在类的private 部分中声明的。这是使类的对象不可赋值的标准习惯用法。

        【讨论】:

          猜你喜欢
          • 2012-01-19
          • 1970-01-01
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          • 2011-07-13
          • 2015-08-06
          • 1970-01-01
          • 2011-11-14
          相关资源
          最近更新 更多