Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ iostream插入器和提取器可以是类成员而不是全局重载吗?_C++_Operator Overloading_Language Design_Iostream_Associativity - Fatal编程技术网

C++ iostream插入器和提取器可以是类成员而不是全局重载吗?

C++ iostream插入器和提取器可以是类成员而不是全局重载吗?,c++,operator-overloading,language-design,iostream,associativity,C++,Operator Overloading,Language Design,Iostream,Associativity,必须声明“全局友元操作符重载”才能进行序列化,这总是让我觉得很笨拙。必须在类之外声明序列化运算符似乎并不重要。所以我一直在寻找一个确切的答案来解释原因 (注:如果有人能在谷歌Fu上找到一个好的答案,我很有兴趣阅读。) 我怀疑这在技术上是可能的,而且只是一个符号问题。如果库被设计为执行的成员重载,那么您必须从右到左而不是从左到右构建一行流式操作。因此,与其写: Rational r (1, 2); cout << "Your rational number is " <<

必须声明“全局友元操作符重载”才能进行序列化,这总是让我觉得很笨拙。必须在类之外声明序列化运算符似乎并不重要。所以我一直在寻找一个确切的答案来解释原因

(注:如果有人能在谷歌Fu上找到一个好的答案,我很有兴趣阅读。)

我怀疑这在技术上是可能的,而且只是一个符号问题。如果库被设计为执行
的成员重载,那么您必须从右到左而不是从左到右构建一行流式操作。因此,与其写:

Rational r (1, 2);
cout << "Your rational number is " << r;
需要使用括号来启动反向链接,因为
>
“您的有理数是”>>cout
之前找到与coder>匹配的“您的有理数是”。如果选择了一名具有以下特征的操作员,则可以避免:

r >>= "Your rational number is " >>= cout;
(注意:在库中,必须使用全局运算符重载处理字符串文字等非类类型。)

但是这就是极限吗?对于任何想要将序列化发送到类中的iostream样式的设计来说,这种逆转几乎是不可避免的?我是否遗漏了其他问题


更新也许“问题”的一个更好的措辞是说我开始怀疑以下几点:

对于希望自己序列化的非流对象,可以假设iostream库的设计使插入器和提取器成为类成员而不是全局重载…并且不会(显著)影响运行时属性。然而,只有当iostream的作者愿意接受它会迫使客户端从右到左形成流操作时,这种方法才会起作用

但我缺乏一种直觉,即为什么全局重载一个操作符和一个成员可以解锁一种本来可以从左到右(而不是从右到左)表达自己的能力。问题是,事后诸葛亮、模板或C++11的某些深奥特性是否能提供另一种选择。或者“C++物理学”对一个方向有着固有的偏见,而全局重载不知何故是本书中覆盖它的唯一编译时技巧


与重载流操作符相比,标准对它们应该是成员还是非成员没有任何限制,因此理想情况下它们可以是成员。事实上,标准库定义的大多数流输出和输入操作符都是流类的成员

理由:

为什么
插入器
提取器
没有作为成员函数重载?

通常,运算符重载的规则是:

如果二元运算符更改其左操作数,则将其设置为左操作数类型的成员函数通常很有用(因为它通常需要访问操作数的私有成员)

根据此规则,流运算符应作为其左操作数类型的成员实现。但是,它们的左操作数是来自标准库的流,不能更改标准库的流类型。因此,当为自定义类型重载这些运算符时,它们通常作为非成员函数实现

我是否遗漏了其他问题

我想不出来,但我得说那已经很糟糕了

通常的
outfile>=cout首先必须向前阅读>>=以查看是否需要跳到最后一个单词(或其附近),阅读“>>=cout”,跳回到字符串开头,向前阅读字符串,等等。而不是将你的眼睛从一个标记移动到下一个标记,在那里大脑能够通过管道传输整个过程

我有几年使用这种非线性语法的语言的经验。我现在正在研究使用CLAN来“编译”C++到该语言中。(尽管原因不止这些。)如果成功了,我会更快乐

我首选的替代方法是一个只调用成员函数的最小运算符重载。即使稍微优化一下,它也会从生成的可执行文件中消失


上述情况有一个“明显”的例外,即在语句中只有一个读/写,如
myobj>>cout

通过将>的定义与正在显示的对象分离,可以获得更大的灵活性

首先,您可能希望自定义显示非类类型,如枚举或指针。假设您有一个类Foo,并且希望自定义打印指向Foo的指针。不能通过向Foo添加成员函数来实现。或者,您可能希望显示模板化对象,但仅显示特定模板参数。例如,您可能希望将向量显示为逗号分隔的列表,而将向量显示为字符串列

另一个原因可能是不允许或不愿意修改现有类。这是OO设计中打开/关闭原则的一个很好的例子,在OO设计中,您希望类为扩展而打开,但为修改而关闭。当然,您的类必须在不破坏封装的情况下公开它的一些实现,但通常情况就是这样(向量公开它们的元素,复数公开Re和Im,字符串公开c_str,等等)


您甚至可以定义C++中两个不同的重载,通常是非类成员。根据Bjarne Stroustrup算子+ C++编程语言,正则表示是一个全局函数,它先复制其左操作数,然后用右操作数将它加上+,然后返回结果。因此,让流操作符是全局的并不是完全不寻常的。如前所述

r >>= "Your rational number is " >>= cout;
class Rock {
    private:
        int weight;
        int height;
        int width;
        int length;

    public:
        ostream& output(ostream &os) const {
            os << "w" <<  weight << "hi" << height << "w" <<  width << "leng" << length << endl;
            return os;
        }
    };

    ostream& operator<<(ostream &os, const Rock& rock)  {
        return rock.output(os);
    }