C++运算符重载说明

C++ Operator overloading explanation

本文关键字:说明 重载 运算符 C++      更新时间:2023-10-16

以下是字符串类的抽象。

class string {
public:
    string(int n = 0) : buf(new char[n + 1]) { buf[0] = ''; }
    string(const char *);
    string(const string &);
    ~string() { delete [] buf; }
    char *getBuf() const;
    void setBuf(const char *);
    string & operator=(const string &);
    string operator+(const string &);
    string operator+(const char *);
    private:
       char *buf;
    };
    string operator+(const char *, const string &);
    std::ostream& operator<<(std::ostream&, const string&);

我想知道为什么这两个运算符重载函数

  string operator+(const char *, const string &);
  std::ostream& operator<<(std::ostream&, const string&);

不是类成员函数或友元函数吗?我知道两个参数运算符重载函数通常是朋友函数(我不确定,如果您也能对此有所启发,我将不胜感激),但是我的教授也没有将它们声明为朋友。以下是这些函数的定义。

 string operator+(const char* s, const string& rhs) {
           string temp(s);
           temp = temp + rhs;
           return temp;
 }
 std::ostream& operator<<(std::ostream& out, const string& s) {
     return out << s.getBuf();
 }

谁能用一个小例子来解释这一点,或者引导我提出类似的问题。提前谢谢。Regards

friend 关键字授予对classprotectedprivate成员的访问权限。在您的示例中未使用它,因为这些函数不需要使用 string 的内部;public接口就足够了。

friend函数从来都不是类的成员,即使在作用域内定义也是如此class {}也是如此。这是一个相当令人困惑的问题。有时friend被用作在class {}大括号内定义非成员函数的技巧。但是在您的示例中,没有什么特别的事情发生,只有两个函数。这些功能恰好是运算符重载。

将一些operator+重载定义为成员,将一些重载定义为

成员,而将一个重载定义为非成员,这是一种糟糕的风格。通过使它们全部成为非成员来改进界面。不同类型的转换规则应用于在重载函数内部变得this的左侧参数,这可能会导致令人困惑的错误。所以交换算子通常应该是非成员(friend或不是)。

让我们谈谈运算符 +。将其作为非成员允许如下代码

string s1 = "Hi";
string s2 = "There";
string s3;
s3 = s1 + s2;
s3 = s1 + "Hi";
s3 = "Hi" + s1;

如果 operator+ 是成员而不是命名空间作用域函数,则最后一个赋值语句是不可能的。但如果它是一个命名空间范围函数,则字符串文字"Hi"使用转换构造函数"string(const char *);"转换为临时字符串对象,并传递给operator+。

在您的情况下,可以在不使此功能成为朋友的情况下进行管理,因为您有私有成员"buf"的访问器。但通常,如果出于某种原因未提供此类访问器,则需要将这些命名空间范围函数声明为友元。

现在让我们谈谈运算符<<。

这是为 ostream 对象定义的插入运算符。如果他们必须打印用户定义类型的对象,则需要修改 ostream 类定义,不建议这样做。

因此,运算符在命名空间作用域中重载。

在这两种情况下,都有一个众所周知的参数相关查找原则,这是查找这些命名空间作用域函数(也称为 Koenig 查找)背后的核心原因。

另一个有趣的读物是命名空间接口原则

运算符可以被成员函数和独立(普通)函数重载。独立重载函数是否是朋友完全无关紧要。友谊属性与操作员超载完全无关。

使用独立函数时,可能需要直接访问类的"隐藏"(私有或受保护)内部,此时将函数声明为 friend 。如果您不需要这种特权访问(即您可以在类的公共接口方面实现所需的功能),则无需将该函数声明为 friend

仅此而已。

将独立的重载函数声明为朋友变得如此流行,以至于人们经常称之为"朋友函数重载"。这确实是一个误导性的用词不当,因为正如我上面所说,友谊本身与它无关。

此外,人们有时会将重载函数声明为friend,即使他们不需要对类的特权访问权限。他们这样做是因为friend函数声明可以将函数的即时内联定义直接合并到类定义中。没有friend一个人将被迫做一个单独的声明和一个单独的定义。在某些情况下,紧凑的内联定义可能看起来"更干净"。

我对C++重载有点生疏,但我会通过这个简单的备忘录完成上述答案:

  • 如果左侧操作数的类型是用户定义的类型(例如类),则应(但不必)将运算符重载实现为成员函数。请记住,如果这些重载(很可能像 ++=++...)修改左侧操作数,它们将返回对调用类型的引用(实际上是在修改后的对象上)。这就是为什么,例如在 Copleen 的规范形式中,operator=重载是一个成员函数并返回一个"UserClassType &"(因为实际上该函数返回 *this )。

  • 如果左侧操作数的类型是系统类型intostream等),则应将运算符重载实现为独立函数。

顺便说一句,我一直被告知friend关键词是坏的,丑陋的,吃孩子。我想这主要是编码风格的问题,但我建议您在使用时要小心,并尽可能避免使用它。(我从未遇到过强制使用它的情况,所以我真的说不出来!

(对不起,我的英语不好,我也有点生疏)

镰刀