C++ 在设计API时,如何使用const和volatile设计重载成员函数?
假设您正在编写一个小型库或API,它将分发给其他程序, 这意味着您永远不知道其他程序员将如何创建对象:这样的对象是常量、volatile、const volatile还是仅仅是一个普通对象 通常,当我们声明某个类时,我们会这样做:C++ 在设计API时,如何使用const和volatile设计重载成员函数?,c++,api,C++,Api,假设您正在编写一个小型库或API,它将分发给其他程序, 这意味着您永远不知道其他程序员将如何创建对象:这样的对象是常量、volatile、const volatile还是仅仅是一个普通对象 通常,当我们声明某个类时,我们会这样做: class A // THIS CLASS DOES NOT SUPPORT ANYTHING { public: int get() { return x; } private: int x; }; 但是,如果希望类支持常量对象,将使用常量限定符重
class A // THIS CLASS DOES NOT SUPPORT ANYTHING
{
public:
int get() { return x; }
private:
int x;
};
但是,如果希望类支持常量对象,将使用常量限定符重载成员函数:
class B // THIS CLASS SUPPORTS CONST OBJECTS
{
public:
int get() { return x; }
int get() const { return x; }
private:
mutable int x;
};
更进一步,我们可能还希望为我们的类支持volatile而不是const:
class C // THIS CLASS SUPPORTS VOLATILE OBJECTS
{
public:
int get() { return x; }
int get() volatile { return x; }
private:
int x;
};
但若用户使用的对象是常量、易失性或
若用户将同时使用易失性和常量的对象,该怎么办?
那么我们也应该为它添加支持
class D // THIS CLASS SUPPORTS CONST, VOLATILE AND CONST VOLATILE OBJECTS
{
public:
int get() { return x; }
int get() const { return x; }
int get() volatile { return x; }
int get() const volatile { return x; }
private:
mutable int x;
};
现在让我们看看为什么我们希望我们的类有这4个重载:
// EXAMPLE
int main()
{
// figure 1
const A a ;
a.get(); // ERROR
// figure 2
volatile B b;
b.get(); // ERROR
// figure 3
const volatile C c;
c.get(); // ERROR
// figure 4 where we finaly created a super class capable of anything!!
const volatile D d;
d.get(); // NOW IS OK!
cin.ignore();
return 0;
}
在最后一个例子(图4)中,我们可以证明我们的类能够被设置为任何类型的
这意味着其他编程人员在创建类的volatile、const或volatile const对象时不会有问题
我的问题是:
将每种方法重叠四次是一种好的设计实践吗?
若否,原因为何
另外,如果我们的类有20个方法,那么当您将它们全部重载时,它实际上会有80个方法
编辑:
现实世界中的API类会做这样的事情吗?
如果没有,那么如果我们有这样的需要,我们将如何创建该类的volatile或const volatile对象。我的观点是,在现实世界中:
const
应该添加到成员函数中,不要考虑客户机代码是否需要它,而是考虑成员函数所做的操作在概念上是否恒定。这就是所谓的常量正确性:
a。首先,函数应该只做一件事。也许是一件复杂的事情,但可以描述为一个单一的概念
b。然后,问问自己,函数所做的这件事是否改变了对象的可观察状态。如果是,那么函数不应该是常量。如果它不是,则将其声明为常量const
引用,所有这些都将正常工作
请注意,我讨论的是对象的可观察状态,而不是成员变量的实际内容:这是一个实现细节。我的观点是,在现实世界中:
const
应该添加到成员函数中,不要考虑客户机代码是否需要它,而是考虑成员函数所做的操作在概念上是否恒定。这就是所谓的常量正确性:
a。首先,函数应该只做一件事。也许是一件复杂的事情,但可以描述为一个单一的概念
b。然后,问问自己,函数所做的这件事是否改变了对象的可观察状态。如果是,那么函数不应该是常量。如果它不是,则将其声明为常量const
引用,所有这些都将正常工作
请注意,我讨论的是对象的可观察状态,而不是成员变量的实际内容:这是一个实现细节。拥有一个
const
对象是可行的,但我怀疑volatile
会有很多用途。另外,对于简单的getter之类的东西,我总是让我的方法保持常量。正如您所说的:“我怀疑volatile会有很多用途”,至少其中一个可能希望这样,还有“我总是让我的方法保持常量”,如果该方法必须更改内部成员该怎么办?不可能所有的方法都是常量,这样的类就是useles:DI意味着我总是使用简单的、不可修改的方法,const.)拥有一个const
对象是可行的,但我怀疑volatile
是否有很多用途。另外,对于简单的getter之类的东西,我总是让我的方法保持常量。正如您所说的:“我怀疑volatile会有很多用途”,至少其中一个可能希望这样,还有“我总是让我的方法保持常量”,如果该方法必须更改内部成员该怎么办?不可能所有的方法都是常量,这样的类就是useles:DI意味着我总是使用简单的、不可修改的方法,const.)有时指向对象的指针是可变的(volatile通常与内置类型一起使用),这并不要求您的方法是可变的。我从来没有见过那些不稳定的修饰语有什么用处(当然除外)。@AlexandreC说Alexandrescu技术是对一个几乎无用的语言特性的巧妙滥用。太酷了!有时指向对象的指针是可变的(volatile通常与内置类型一起使用),这并不要求您的方法是可变的。我从来没有见过那些不稳定的修饰语有什么用处(当然除外)。@AlexandreC说Alexandrescu技术是对一个几乎无用的语言特性的巧妙滥用。太酷了!