首先,为了解决我的问题,请看看我准备的这两个代码段:
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
void Normalise()
{
float num = (((this->X * this->X) + (this->Y * this->Y)) +
(this->Z * this->Z)) + (this->W * this->W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
this->X *= num2;
this->Y *= num2;
this->Z *= num2;
this->W *= num2;
}
void Conjugate()
{
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
};
以上是我在标题中提到的班级中的“本地方法”。 现在让我们看一下课堂内“静态方法”的含义。
struct Quaternion
{
public:
float X, Y, Z, W;
Quaternion(float x, float y, float z, float w)
:
X(x), Y(y), Z(z), W(w)
{}
static Quaternion& Normalise(Quaternion& quat)
{
float num = (((quat.X * quat.X) + (quat.Y * quat.Y)) +
(quat.Z * quat.Z)) + (quat.W * quat.W);
float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
// Assuming operator= overloaded..
quat = Quaternion(quat.X * num2, quat.Y * num2, quat.Z * num2, quat.W * num2);
return quat;
}
static Quaternion& Conjugate(Quaternion& quat)
{
// Assuming operator= overloaded..
quat = Quaternion(-quat.X, -quat.Y, -quat.Z, quat.W);
return quat;
}
};
我的问题是......什么是权衡?效果?要使用这些静态类方法而不是本地方法。两者都有类似的用法:
编辑:忽略* .ToString功能,它是伪代码 - 我相信你可以想象它会做什么;因此它的实现是多余的,因为它只打印出原始的X,Y,Z,W值。
'本地方法'类用法:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat.Conjugate();
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
现在'静态方法'类用法:
int main()
{
Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);
std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)
testQuat = Quaternion::Conjugate(testQuat);
std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)
return 0;
}
那有什么区别?这些是静态方法而不是对象。哪个更好?这仅仅是设计选择的问题吗?
答案 0 :(得分:3)
它们是两个完全不同的东西。其中一个修改了对象 a la OOP ,另一个返回一个不同的对象一个功能样式。如果这是我的选择,我会保留它们两个,因为它们都有用例。我将基于成员函数将函数样式实现为自由函数,即:
Quaternion normalize( Quaternion quat )
{
quat.normalize();
return quat;
}
[我在这里明确地按quat
取值,给出了复制省略的机会]
请注意,您的静态实现是错误的,它们返回对临时的引用。这是未定义的行为,你应该从你的编译器得到一个警告,如果你幸运的话也会发生运行时崩溃。
答案 1 :(得分:1)
首先,你的第二种方法不应该编译,尽管我认为MSVC ++有一个错误,允许临时对象绑定到非const
引用。即使添加const&
也不能使函数更好:它们仍然无法工作,因为调用者获得了对临时函数的引用。非常适合实施。
关于界面设计,我认为真正的权衡不在static
成员之间(如果你愿意的话,你可以另外拥有它们)但是不带参数的函数是否应该改变对象本身或者应该返回相应修改的对象:
// return a copy:
Quaternion Quaternion::conjugate() const {
return Quaternion(-this->X, -this->Y, -this->Z, this->W);
}
// modify the object itself:
void Quaternion::conjugate() {
this->X = -this->X;
this->Y = -this->Y;
this->Z = -this->Z;
}
虽然这两个过载实际上可以生活在同一个班级,但我不提供这两个版本!它是界面的选择,哪一个是优选的。我个人更喜欢后者,可能会创建一个static
成员来改变对象本身:
/* static */ void Quaternion::conjugate(Quaternion& object) {
object = object.conjugate();
}
答案 2 :(得分:0)
除了关于两种方法之间差异的其他答案之外,如果你想在单元测试中使用静态方法很难模拟/存根。
例如,假设您有一个名为ClassThatUsesQuaternion的类,它使用Quaternion。如果Quaternion有很多静态方法,您将始终拥有真实数据。另一方面,如果将Quaternion方法转换为虚方法,则可以重新定义所有方法,在您的控制下创建环境测试。您甚至可以添加一个像gmock这样的模拟框架来满足您的期望。