C++ 编程/类/良好类
一个“良好”的类考虑了以下函数的使用
1. 复制构造函数。
2. 赋值运算符。
3. 相等运算符。
4. 不相等运算符。
class Nice
{
public:
Nice(const Nice &Copy);
Nice &operator= (const Nice &Copy);
bool operator== (const Nice ¶m) const;
bool operator!= (const Nice ¶m) const;
};
一个“良好”的类也可以称为容器安全类。许多容器,例如我们将在后面看到的标准模板库(STL) 中的那些容器,在与你的类的对象交互时使用复制构造和赋值运算符。如果默认行为(按成员进行逐个复制,而不是按二进制复制)不可取或不足以正确地复制/构造你的对象,则只需声明和定义赋值运算符和复制构造函数。
一个普遍的经验法则是,如果默认的按成员进行逐个复制操作不适用于你的对象,那么你应该定义一个合适的复制构造函数和赋值运算符。如果两者中任何一个被定义,则它们都需要。
复制构造函数的目的是允许程序员执行与赋值运算符相同的指令,特殊情况是知道调用者正在初始化/构造而不是复制。
在使用复制构造函数时使用 explicit 关键字也是一个好习惯,以防止意外的隐式类型转换。
示例
class Nice
{
public:
explicit Nice(int _a) : a(_a)
{
return;
}
private:
int a;
};
class NotNice
{
public:
NotNice(int _a) : a(_a)
{
return;
}
private:
int a;
};
int main()
{
Nice proper = Nice(10); //this is ok
Nice notproper = 10; //this will result in an error
NotNice eg = 10; //this WILL compile, you may not have intended this conversion
return 0;
}
相等运算符表示“这个对象是否等于那个对象?”。 什么构成相等由程序员决定。 这是如果你想用你类中的对象使用相等运算符的必要条件。
但是,在大多数应用(例如数学)中,通常情况下,对不相等进行编码比对相等进行编码更容易。在这种情况下,以下代码可以为相等编写。
inline bool Nice::operator== (const Nice& param) const
{
return !(*this != param);
}
不相等运算符表示“这个对象是否不等于那个对象?”。 什么构成不相等由程序员决定。 这是如果你想用你类中的对象使用不相等运算符的必要条件。
但是,在某些应用中,对相等进行编码比对不相等进行编码更容易。在这种情况下,以下代码可以为不相等编写。
inline bool Nice::operator!= (const Nice& param) const
{
return !(*this == param);
}
如果关于(不)相等运算符具有不同效率(无论哪种)的陈述对你来说完全是胡说八道,请考虑通常,所有对象属性必须匹配,两个对象才能被认为是相等的。
通常,只有当两个对象要被认为是不相等时,一个对象属性必须不同。对于相等和不相等运算符,这并不意味着一个是比另一个更快的。
但是,请注意,使用上面定义的相等和不相等函数会导致无限递归循环,因此必须小心,只使用其中一个。此外,还有一些情况是两者都不适用,因此上面两种方法都无法使用。
给定两个对象 A 和 B(具有类属性 x 和 y),相等运算符可以写成
if (A.x != B.x) return false;
if (A.y != B.y) return false;
return true;
而不相等运算符可以写成
if (A.x != B.x) return true;
if (A.y != B.y) return true;
return false;
所以,是的,相等运算符当然可以写成...!(a!=b)...,但它并没有更快。事实上,这里还增加了方法调用和否定操作的开销。
因此问题变成了,少量执行开销是否值得更小的代码和更好的可维护性?对此没有简单的答案,它完全取决于程序员如何使用它们。如果你的类包含,比如,一个包含 10 亿个元素的数组,那么开销是微不足道的。