我不明白在此示例中何时调用构造函数

时间:2019-11-18 16:51:53

标签: c++

嗨,我一直在尝试分析以下使用操作重载的代码。

#include <iostream>
using namespace std;

#define DBG(str) cout << str << endl

class Integer {
    int n;
public:
    Integer(int _n) : n(_n) { DBG("A"); };
    Integer(const Integer& i) : n(i.n) { DBG("B"); };

    Integer& operator=(const Integer& i) { DBG("C"); n = i.n; return *this; };
    Integer& operator+=(const Integer& i) { DBG("D"); n += i.n; return *this; };

    friend Integer operator+(const Integer& a, const Integer& b);
    friend Integer operator*(const Integer& a, const Integer& b);
    friend ostream& operator<<(ostream& os, const Integer& i);

};

Integer operator+(const Integer& a, const Integer& b) {
    DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
    DBG("F"); return Integer(a.n * b.n);
}
ostream& operator<<(ostream& os, const Integer& i) {
    DBG("G"); os << i.n; return os;
}

int main() {
    Integer n1(1), n2(2);
    Integer n = 5 + n1 + 2 * n2;

    cout << n << endl;
}

结果是...

A // constructor called when n1 is created
A // constructor called when n2 is created
A // when is this called?
A // when is this called?
F // called when 2 * n2 is operated
A // called when Integer(a.n * b.n) is created in the multiplication function
E // called when 5 + n1 is operated
A // called when Integer(a.n + b.n) is created in the addition function
E // called when (5 + n1) + (2 * n2) is operated
A // called when Integer is created in the addition function
G // called when n is printed using cout
5 // value of n

现在最困扰我的是A的第三和第四张印刷品。在句子Integer n = 5 + n1 + 2 * n2;中,正在创建对象n并将正确的值分配给n,因此复制构造函数应叫做?我认为应该发生的是应调用构造函数以创建(5 + n1 + 2 * n2)的临时对象,然后将其复制到n,然后调用复制构造函数。我理解错了什么?

请您说明发生了什么?预先谢谢你。

3 个答案:

答案 0 :(得分:6)

问题在这一行:

Integer n = 5 + n1 + 2 * n2;

对于operator+int没有Integer,但是编译器在默认情况下从intInteger默默地执行了implicit conversion所有单参数构造函数都可以用作转换方法。 这是your live code(已改进)。

这是C ++的危险特性之一,因此在构造函数之前必须使用explicit关键字。如果添加它:

explicit Integer(const Integer& i) : n(i.n) { DBG("B"); };

由于现在无法执行隐式转换并且没有operator+(int, const Integer&)operator*(int, const Integer&),编译器将报告错误。

答案 1 :(得分:3)

您的operator+operator*函数接收一个const Integer&作为参数。

计算此行(5 + n1 + 2 * n2)5和2将自动转换为Integer

如果不希望它们转换,则应考虑为int作为参数创建运算符。

编辑:您还可以使用显式构造函数。

例如:explicit Integer(int _n){...}

///感谢您的评论@ formerlyknownas_463035818

答案 2 :(得分:1)

仅当运算符的第一个参数不是为其定义运算符的目标类的对象时,才在运算符重载中使用朋友函数。 就您而言,Integer

Integer operator+(const Integer& a, const Integer& b) {
    DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
    DBG("F"); return Integer(a.n * b.n);
}

,第一个参数确实是Integer类型的对象,它是您的目标类。您可能想要的是能够将Integer对象与原始整数类型一起用作操作数。 将您的朋友功能签名更改为:

Integer operator+(const int& a, const Integer& b) {
    DBG("E"); return Integer(a + b.n);
}
Integer operator*(const int& a, const Integer& b) {
    DBG("F"); return Integer(a * b.n);
}

请注意,使用a代替a.n是因为当将运算符函数定义为好友时,两个操作数均作为参数传递。(与非好友运算符函数不同,第一个运算数是调用者宾语)。因此a包含类型为int的值,而不包含类型为Integer的值。

  

对包含DBG("A")的构造函数的匿名调用是将5和2从int转换为Integer时发生隐式转换的结果。

这不可靠,尽管您的代码可能有效。 希望这会有所帮助。