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 ();
...
}
};
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
型 这个僵尸类反对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_;
};
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;
}
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;
}
}
6条答案
按热度按时间ntjbwcob1#
是的,你可以这样做。你只需要验证构造函数体中的参数。如果它们无效,那么抛出异常。
字符串
bvjveswy2#
你可以这样做:
字符串
等等。注意一个重要的点,如果在构造函数中抛出异常,析构函数将不被调用(尽管任何基类析构函数将被调用)。这是内存泄漏的一个相当常见的原因。
w8ntj3qf3#
在我开始之前,我想澄清这实际上是C++中一个相当大的主题,许多设计模式都是围绕这个问题显式设计的。
一个更好的方法是在构造器中抛出一个异常:
字符串
这通常被认为是一个不好的习惯,因为类的析构函数永远不会被调用!根据经验,构造函数应该快速简单。如果构造函数可能失败,你应该尝试其他方法。此外,异常处理在C++中是出了名的慢。
所以很多人会使用初始化调用:
型
然后,当你使用这个类时,你可以在初始化尝试后检查对象是否成功。
型
我个人不喜欢这样,因为你最终与僵尸类。
型
这个僵尸类反对RAII的想法,老实说,我不应该做检查所有的时间。
我喜欢的处理方法是工厂方法。
型
(protip不要使用原始指针,使用智能指针)。
8cdiaqws4#
您可以使用static_assert来实现编译时检查,但可能必须将调用 Package 在一个丑陋的宏中,或者 Package 在模板中。
类似于(希望不那么丑陋):
字符串
6qftjkof5#
因为你在写程序的时候就知道了可接受值的范围,所以试图用不正确的值构造类意味着你的程序已经失败了。你应该使用Assert。Assert用于记录类/函数/等的正确用法,并简化调试过程。
http://www.cplusplus.com/reference/cassert/assert/
字符串
assert
将抛出一个异常,如果你传递给它的布尔值为false。通过说
assert(a > 1 && b > 2 && c > 2);
,你是说“程序永远不应该用超出正确范围的a、b和c的值来构造myClass”。如果程序这样做了,程序是不正确的。这将使你很容易找到并纠正错误。如果值来自于你无法控制的地方,比如用户输入,你应该在myClass的构造函数之外验证输入。这是正确的关注点分离。
使用
assert
的另一个优点是,当你编译你的发布/优化版本时,Assert将计算为null语句。这样,旨在帮助你调试的代码将不会减慢你的发布版本。记住
#include <assert.h>
。vbkedwbf6#
我就是这么做的
字符串