命名构造函数
您可以使用所谓的命名构造函数(另请参阅https://isocpp.org/wiki/faq/ctors#named-ctor-idiom),并制作构造函数private
:
class RenderTarget {
private:
RenderTarget (int w, int h) :
width_(w), height_(h), buffer_(w*h)
{
// NOTE: Error checking completely removed.
}
public:
static RenderTarget create(int width, int height) {
// Constraint Checking
if (width<0 || height<0)
throw std::logic_error("Crizzle id boom shackalack");
return RenderTarget(width, height);
}
如果您有多个使用起来可能不明确的构造函数,命名构造函数会很有趣,例如Temperature <-- Celsius | 华氏度 | 开尔文或距离 <-- 米 | 院子 | 肘 | 公里 | ... .
否则,(个人意见)它们会带来意想不到的抽象和分心,应该避免。
三元运算符和throw
C++ 允许在[expr.cond]中throw
在三元运算符 (-operator) 的一个或两个操作数中使用 - 表达式?:
:
RenderTarget(int w, int h) :
width_(w<0 ? throw std::logic_error("Crizzle id boom shackalack") : w),
height_(h<0 ? throw std::logic_error("Crizzle id boom shackalack") : h),
surface_(w*h)
{}
如果不存储参数,?:
当然也可以在表达式内部使用:
RenderTarget(int w, int h) :
surface_(
(w<0 ? throw std::logic_error("Crizzle id boom shackalack") : w)
* (h<0 ? throw std::logic_error("Crizzle id boom shackalack") : h)
)
{}
或者您将前置条件检查组合成一个操作数:
RenderTarget(int w, int h) :
surface_(
(w<0||h<0) ? throw std::logic_error("Crizzle id boom shackalack") :
w * h
)
{}
将?:
-operator 与throw
-expression内联使用对于基本的约束检查非常好,并且避免不得不回退到使用默认构造函数(如果有的话),然后在构造函数体内进行“真正的初始化”。
对于更复杂的场景,这可能会变得有点笨拙。
静态私有成员
当然,可以使用两全其美:
private:
static bool check_preconditions(int width, int height) {
if (width<0 || height<0)
return false;
return true;
}
public:
RenderTarget(int w, int h) :
surface_(
check_preconditions(w,h) ?
w*h :
throw std::logic_error("Crizzle id boom shackalack")
)
{}
...或者您为需要进行前置条件检查的任何成员编写静态函数:
private:
static Buffer create_surface(int width, int height) {
if (width<0 || height<0)
throw std::logic_error("Crizzle id boom shackalack")
return Buffer(width*height);
}
public:
RenderTarget(int w, int h) :
surface_(create_surface(w, h))
{}
这很好,因为您手头有完整的 C++ 机器来进行约束检查,例如可以轻松添加日志记录。它可以很好地扩展,但对于简单的场景来说不太方便。