如何检查类中传递的参数是否正确

时间:2014-11-14 15:52:27

标签: c++

假设以下代码:

class myClass{
    myClass(int a, int b, int c){};
};

main(){
   myClass cl(2,5,6);
}

myClass cl(2,5,6);将工作。但是如果我希望构造函数只使用特定的值呢?例如,a> 1b> 2c> 1。有没有办法检测错误的参数和"取消"在构造函数中创建cl?

6 个答案:

答案 0 :(得分:5)

是的,你可以这样做。你只需要验证构造函数体内的参数。如果它们无效则抛出异常。

Class Invalid
{
 private:
    int m_x, m_y;
 public :
    class MyException : public exception {};

    Invalid ( int x, int y )
    {
       if ( x < 0 || y > 100 )
            throw MyException ();
       ...             
    }
}; 

答案 1 :(得分:3)

您可以这样做:

myClass(int a, int b, int c)
{
    if (a <= 1){
        throw something; // ToDo - define `something`, a text string would work.
    }
}

等等。请注意一点,如果在构造函数中抛出异常,则析构函数将被调用(尽管将调用任何基类析构函数 )。这是导致内存泄漏的常见原因。

答案 2 :(得分:1)

在开始之前,我想澄清一下,这实际上是C ++中一个非常重要的主题,许多设计模式是围绕这个问题明确设计的。

nieve方法是在构造函数中抛出异常:

class myClass {
public:
  myClass(int a, int b, int c) 
  {
    if (a<=1 || b <= 2 || c<=1) throw "some exception";
  }
};

这通常被认为是一种不好的做法,因为该类的析构函数永远不会被调用!根据经验,构造函数应该快速而简单。如果构造函数失败,您应该尝试其他方法。此外,C ++中异常处理的速度非常慢。

所以有很多人改为使用初始化调用:

class myClass {
  public:
     myClass() { initialized_ = true;}
     void initialize((int a, int b, int c) { initialized_ = !(a<=1 || b <= 2 || c<=1);}
     bool alive() {return intialized_;}
  private:
     bool initialized_;
 };

然后,当您使用该类时,如果对象成功,您可以在初始化尝试后进行检查。

 myClass c;
 c.initialize(2,5,6);

我个人不喜欢这样,因为你最终得到了僵尸类。

 myClass c;
 c.initialize(0,0,0);
 c.foo();//Legal, compiles, but is WRONG

这个Zombie Class提出了RAII的想法,说实话,我不应该一直这样做。

我处理这个问题的首选方法是工厂方法。

 class myClass
 {
 public:
    static myClass* makeMyClass(int a, int b, int c)
    {
       myClass* ret = new myClass();
       ret->initialize(a,b,c);
       if (!ret->alive()) {delete ret; return null;}
       return ret;
    }
 private:
    myClass() { initialized_ = true;}
     void initialize((int a, int b, int c) { initialized_ = !(a<=1 || b <= 2 || c<=1);}
     bool alive() {return intialized_;}
  private:
     bool initialized_;
 };

(protip不使用原始指针,使用智能指针)。

答案 3 :(得分:0)

您可以使用static_assert来实现编译时间检查,但也许您必须将您的调用包装在一个丑陋的宏中,或者包含在模板中。

喜欢(希望不那么丑陋):

class myClass{
public:
  myClass(int a, int b, int c){};
};

#define SafeMyClass(obj, a,b,c) static_assert(a<b,"a<b"); static_assert(b<c,"b<c"); myClass obj(a,b,c);

int main(){
  SafeMyClass(cl,2,5,6);
  return 0;
}

答案 4 :(得分:0)

由于您在程序编写时知道可接受值的范围,因此尝试使用不正确的值构造类意味着您的程序已损坏。你应该使用一个断言。断言用于记录类/函数/等的正确用法,并简化调试过程 http://www.cplusplus.com/reference/cassert/assert/

class myClass{
    myClass(int a, int b, int c) {
        assert(a > 1 && b > 2 && c > 2); 
    };
};
如果传递给它的布尔值计算为false,

assert将抛出异常。

通过说assert(a > 1 && b > 2 && c > 2);你说“程序永远不应该构造myClass,其中a,b和c的值超出了正确的范围”。如果程序这样做,程序是不正确的。这将使您很容易找到并纠正错误。

如果值来自您无法控制的某个地方,例如用户输入,则应在myClass的构造函数之外验证该输入。这是关注点的正确分离。

使用assert的另一个好处是,当您编译发布/优化版本时,断言将评估为null语句。这种用于帮助您调试的代码不会减慢您的发布版本。

请记住#include <assert.h>

答案 5 :(得分:0)

我就是这样做的

 class myClass{
    public:
        myClass(int a, int b, int c):aValue(a), bValue(b), cValue(c){};
    private:
        int aValue;
        int bValue;
        int cValue;
 };

 myClass::myClass(int a, int b, int c){
     if(a<2) throw rangeError("the 'a' should be larger than one");
     if(b<3) throw rangeError("the 'b' should be larger than one");
     if(c<2) throw rangeError("the 'c' should be larger than one");
 }

 void main(){
    try{
        myClass cl(2,5,6);
    }catch(rangeError re){
        cout << re.what() << endl;
    }
 }