为什么 std::basic_ostream::operator<< 不是 const 限定的?
why is std::basic_ostream::operator<< not const-qualified?
首先,举个例子来说明我的问题背后的道理:下面的代码无法编译,因为 std::basic_ostream::operator<< 不符合 const
条件。 (https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-3.4/ostream-source.html 表明运算符不符合 const
条件。)
我使用 GNU g++ 6.4.0 编译器编译,打开了 --std=c++11 标志。
#ifndef TEST_H
#define TEST_H
#include<string>
#include<iostream>
using namespace std;
class ChessPiece{
const string name;
const int side;
public:
ChessPiece(const string&,const int);
void printPiece(const ostream&) const;
};
#endif // TEST_H
...和test.cpp.
#include"test.h"
ChessPiece::ChessPiece(const string& s,const int bw): name{s}, side{bw} {}
void ChessPiece::printPiece(const ostream& S=cout) const{
S << "a " << (side==1?"white ":"black ") << name << endl;
}
int main(){
ChessPiece p{string("pawn"),-1}; // a black pawn
p.printPiece();
}
但是,我不确定为什么首先会出现这些类型的错误,即使 operator<< 在逻辑上如上述代码所示 const
。
是的,显而易见的答案是“operator<<
以某种方式改变了 std::ostream
的内部状态”。
但是,我知道通过使成员 mutable
我们可以更改 class 的内容,只要 const
-限定函数在逻辑上是 const
.我还知道 std::ostream
的实例在调用它的 operator<<
之前和之后在逻辑上不会有任何不同。 (如有错误请指出,谢谢)
改写,
为什么逻辑上 const
std::basic_ostream::operator<< 不是 const
限定的,而不是让它的一些成员可变?
提前致谢。
std::ostream
将 在调用其 operator<<
后以外部可见的方式有所不同。大多数时候,tellp
方法将 return 更新值(同样,使用 cur
作为第二个参数的 seekp
的结果会有所不同)。
即使是流输出(所以"position"是一个无意义的概念),各种状态位总是可以变化的,同样,通过good
是外部可见状态的一部分, bad
、fail
和 eof
方法。
此外,ostream
的缓冲区的行为(包括完全换出的能力)在写入内容时会出现不可预测的差异。换出后备缓冲区的行为完全不同,具体取决于它是否为空;如果非空,则不会写入某人写入的数据。由于写入任何类型的更多数据都可以从空缓冲区状态切换到非空缓冲区状态(将小于缓冲区大小的字节写入空缓冲区而没有隐式刷新),以及从非空到空(如果通过填充缓冲区触发刷新)缓冲区或行缓冲流上的换行符),你总是在改变缓冲区的可见状态。
你说:
I also know that an instance of std::ostream
will not logically differ in any way before and after calling its operator<<
.
这是查看 std::ostream
的一种方式。另一种看待它的方式是,它是设备的接口——文件、控制台、字符串等。如果该接口中的成员函数更改了底层设备,则使该成员函数成为 const
成员函数.
const
的概念是概念性的。看一下 ,它稍微探讨了这个主题。是的,可以使 operator<<
函数与 const std::stream
对象一起使用,但它们不是更有意义。他们正在更改为其提供接口的底层设备,IMO,他们最好使用类型为 std::ostream
.
的非 const
对象
我们来看这样的代码:
os << data;
if( !os ) throw std::runtime_exception( "io error" );
虽然 operator<<
的结果通常被忽略,但可能需要检查输出是否成功。很可能编译器将无法优化此检查,但对于作为 reader 的我来说,它变得不清楚,为什么我需要在调用 const
方法后重新检查对象的状态。因此,将这些方法标记为 const
会损害界面的可读性,并且不会产生任何好处,显然这些调用在概念上不是 const
。
注意:为优化 const
方法调用而不改变可观察行为的能力添加了可变成员(昂贵操作的缓存结果和 return 缓存值,如果对象的状态没有改变),使用mutable
这里是对 const
方法概念的简单滥用
首先,举个例子来说明我的问题背后的道理:下面的代码无法编译,因为 std::basic_ostream::operator<< 不符合 const
条件。 (https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-3.4/ostream-source.html 表明运算符不符合 const
条件。)
我使用 GNU g++ 6.4.0 编译器编译,打开了 --std=c++11 标志。
#ifndef TEST_H
#define TEST_H
#include<string>
#include<iostream>
using namespace std;
class ChessPiece{
const string name;
const int side;
public:
ChessPiece(const string&,const int);
void printPiece(const ostream&) const;
};
#endif // TEST_H
...和test.cpp.
#include"test.h"
ChessPiece::ChessPiece(const string& s,const int bw): name{s}, side{bw} {}
void ChessPiece::printPiece(const ostream& S=cout) const{
S << "a " << (side==1?"white ":"black ") << name << endl;
}
int main(){
ChessPiece p{string("pawn"),-1}; // a black pawn
p.printPiece();
}
但是,我不确定为什么首先会出现这些类型的错误,即使 operator<< 在逻辑上如上述代码所示 const
。
是的,显而易见的答案是“operator<<
以某种方式改变了 std::ostream
的内部状态”。
但是,我知道通过使成员 mutable
我们可以更改 class 的内容,只要 const
-限定函数在逻辑上是 const
.我还知道 std::ostream
的实例在调用它的 operator<<
之前和之后在逻辑上不会有任何不同。 (如有错误请指出,谢谢)
改写,
为什么逻辑上 const
std::basic_ostream::operator<< 不是 const
限定的,而不是让它的一些成员可变?
提前致谢。
std::ostream
将 在调用其 operator<<
后以外部可见的方式有所不同。大多数时候,tellp
方法将 return 更新值(同样,使用 cur
作为第二个参数的 seekp
的结果会有所不同)。
即使是流输出(所以"position"是一个无意义的概念),各种状态位总是可以变化的,同样,通过good
是外部可见状态的一部分, bad
、fail
和 eof
方法。
此外,ostream
的缓冲区的行为(包括完全换出的能力)在写入内容时会出现不可预测的差异。换出后备缓冲区的行为完全不同,具体取决于它是否为空;如果非空,则不会写入某人写入的数据。由于写入任何类型的更多数据都可以从空缓冲区状态切换到非空缓冲区状态(将小于缓冲区大小的字节写入空缓冲区而没有隐式刷新),以及从非空到空(如果通过填充缓冲区触发刷新)缓冲区或行缓冲流上的换行符),你总是在改变缓冲区的可见状态。
你说:
I also know that an instance of
std::ostream
will not logically differ in any way before and after calling itsoperator<<
.
这是查看 std::ostream
的一种方式。另一种看待它的方式是,它是设备的接口——文件、控制台、字符串等。如果该接口中的成员函数更改了底层设备,则使该成员函数成为 const
成员函数.
const
的概念是概念性的。看一下 operator<<
函数与 const std::stream
对象一起使用,但它们不是更有意义。他们正在更改为其提供接口的底层设备,IMO,他们最好使用类型为 std::ostream
.
const
对象
我们来看这样的代码:
os << data;
if( !os ) throw std::runtime_exception( "io error" );
虽然 operator<<
的结果通常被忽略,但可能需要检查输出是否成功。很可能编译器将无法优化此检查,但对于作为 reader 的我来说,它变得不清楚,为什么我需要在调用 const
方法后重新检查对象的状态。因此,将这些方法标记为 const
会损害界面的可读性,并且不会产生任何好处,显然这些调用在概念上不是 const
。
注意:为优化 const
方法调用而不改变可观察行为的能力添加了可变成员(昂贵操作的缓存结果和 return 缓存值,如果对象的状态没有改变),使用mutable
这里是对 const
方法概念的简单滥用