-3

构造函数中的这种情况是正确的还是有更好的方法来做到这一点?

class Foo {
    public: Foo(int y) {
        if (y < 0 || y > 99)
           cout << "Error! Invalid input" << endl;

        else
            x = y;
        }

    private: int x;
    };
4

5 回答 5

5

C++ 中在构造时验证对象(即防止创建无效对象)的一般模式是在构造函数中抛出异常。这样,您可以保证如果您有一个 Foo 类型的对象,它将被正确初始化或根本不被创建。

所以你会做一些类似的事情:

class Foo{
    public: Foo(int y) {
        if (y < 0 || y > 99)
           throw std::invalid_argument("y out of range");
        x = y;
    }

};

在实例化时,您可以捕获如下异常:

try
{
    Foo f(100);
    // do stuff with f
}
catch(std::invalid_argument& e)
{
    std::cout << "Construction of Foo failed" << std::endl;
}

如果你没有捕捉到它,它就会冒泡,你可以在更高的层次上捕捉到它,或者根本不捕捉它,这将导致中止并退出应用程序。一般来说,异常应该被捕获在一个明显的地方,即如何正确地对异常情况做出反应(比如在最简单的情况下向用户显示错误并继续执行)。

于 2013-09-05T18:26:43.467 回答
4

不,如果你有构造函数的先决条件,你可以检查它们,但如果它们失败,你应该抛出异常或中止,而不仅仅是输出到std::cout. 使用 assert( y >= 0 && y <= 99 )将是这样做的典型方式。(您永远不应该将错误消息输出到std::cout。)

于 2013-09-05T18:27:03.327 回答
2

在您的情况下,尽管出现错误消息,您的构造函数仍将“工作” - 它会创建对象,但状态无效。您可以使用异常来防止创建您的对象,因此您不会对现有的无效状态对象产生问题。

class InvalidInputException: public std::exception {
      // ...
};

class Foo{
    public: Foo(int y) {
        if (y < 0 || y > 99)
           throw InvalidInputException();
        x = y;
    }

};

// Test:


try
{
    Foo f(param);
}
catch(InvalidInputException& e)
{
    std::cerr << "Invalid input!" << std::endl;
}

此外,您不需要创建自己的异常类。标准库可能有适合您的异常类型,例如std::runtime_errorstd::logic_error(及其子类)。

于 2013-09-05T18:26:20.417 回答
1

您可能希望为这样的事情使用工厂设计模式。它看起来像这样:

class Foo 
{
   private:
      int x;

      Foo(int y) 
      {
         x = y;
      }

   public:
      static Foo* GenerateFoo(int y)
      {
         Foo* newFoo = NULL;

         if(y >= 0 && y <= 99)
            newFoo = new Foo(y);

         return newFoo;
      }
}

如果您的输入超出范围,这将导致不会发生创建,而是会返回一个 NULL 指针。请注意,此特定实现将 Foo 对象的存储限制在运行时堆中,并且出于示例目的而过度简化。有关如何实现工厂方法的更多信息。

于 2013-09-05T18:29:22.637 回答
1

这是另一种方法。这个确切的代码假定您不想从构造函数中抛出异常,而是希望有机会检查有效性,并且仅在实际使用无效值时才抛出异常。如果初始化无效值是“正常”情况,而不是任何“异常”情况,则使用这种方法是合理的,否则最好直接从构造函数中抛出。

class Foo { 

public: 

    Foo(int y) : 
        valid(y >= 0 && y <= 99), 
        x(valid ? y : -1) // use -1 as invalid value marker
    { 
        // note: doing cout output from constructor is... unusual
        if (!valid)
            cout << "Error! Invalid input" << endl;
    }

    bool isValid() {
        return valid;
    }

    int getX() {
        if (!valid) throw something;
        return x;
    }

private:
    bool valid;
    int x;
}

请注意该代码还如何使用构造函数初始化程序列表。在这种情况下,成员变量的顺序validx重要,valid必须在之前,x因为它的值在初始化时使用x

于 2013-09-05T18:55:36.627 回答