假设以下代码:
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?
答案 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;
}
}