C ++运算符重载说明

时间:2013-01-24 03:15:59

标签: c++ operator-overloading

以下是字符串类的抽象。

class string {
public:
    string(int n = 0) : buf(new char[n + 1]) { buf[0] = '\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();
 }

任何人都可以用一个小例子来解释这个问题,或者引导我提出类似的问题。提前致谢。 此致

4 个答案:

答案 0 :(得分:2)

我们来谈谈运营商+。将其作为非成员允许使用以下代码

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

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

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

在您的情况下,可以管理而不将此功能设为朋友,因为您拥有私人会员'buf'的访问者。但通常,如果由于某种原因未提供此类访问器,则需要将这些命名空间范围函数声明为朋友。

现在让我们谈谈运营商&lt;&lt;。

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

因此,运算符在命名空间范围内过载。

在这两种情况下,都有一个众所周知的Argument Dependent Lookup原则,这是查找这些命名空间范围函数的核心原因,也称为Koenig Lookup。

另一个有趣的读物是Namespace Interface Principle

答案 1 :(得分:2)

friend关键字授予对protected的{​​{1}}和private成员的访问权限。它没有在您的示例中使用,因为这些函数不需要使用class的内部; <{1}}界面就足够了。

string函数永远不是类的成员,即使在public范围内定义也是如此。这是一个相当令人困惑的问题。有时friend用作在class {}括号内定义非成员函数的技巧。但在你的例子中,没有什么特别的东西,只有两个功能。而且这些功能碰巧是操作员超载。

样式不好将某些friend重载定义为成员,而另一个重定义为非成员。通过使所有这些成员成为非成员来改进界面。不同的类型转换规则应用于在重载函数内变为class {}的左侧参数,这可能导致混乱的错误。因此,可交换运营商通常应该是非成员(operator+或不成员)。

答案 2 :(得分:1)

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

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

这就是它的全部。

声明一个独立的重载功能,因为朋友变得如此受欢迎,以至于人们经常称之为“由朋友功能超载”。这真是一个误导性的误称,因为正如我上面所说,友谊本身与它无关。

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

答案 3 :(得分:0)

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

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

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

顺便说一下,我总是被告知friend关键字是坏的,丑陋的并且吃孩子。我想这主要是编码风格的问题,但我建议你在使用它时要小心,并尽可能避免使用它。 (我从来没有遇到过强制使用它的情况,所以我无法说出来!)

(抱歉我的英语不好,我也有点生气)

SCY