代码:

#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double r, double i);
Complex(Complex& c);
Complex add(Complex c);
void print(void);
private:
double real, image;
};
Complex::Complex(double r, double i) :real(r), image(i)
{
cout << "调用两个参数的构造函数" << endl;
}
Complex::Complex(Complex& c)
{
real = c.real;
image = c.image;
cout << "调用拷贝构造函数" << endl;
}
void Complex::print(void)
{
cout << "(" << real << "," << image << ")" << endl;
}
Complex Complex::add(Complex c)
{
Complex y(real + c.real, image + c.image);
return y;
}
void f(Complex n)
{
cout << "n=";
n.print();
}
void main(void)
{
Complex a(3.0, 4.0), b(5.6, 7.9);
Complex c(a);
cout << "a=";
a.print();
cout << "c=";
c.print();
f(b);
c = a.add(b);
c.print();
}

运行代码后显示:

调用两个参数的构造函数
调用两个参数的构造函数
调用拷贝构造函数
a=(3,4)
c=(3,4)
调用拷贝构造函数
n=(5.6,7.9)
调用拷贝构造函数
调用两个参数的构造函数
(8.6,11.9)

分析程序的主要运行过程:

  1. 初始化对象 aa: 使用Complex(double r, double i)构造函数,传入3.04.0作为参数,初始化对象 aa 的成员变量realimage。输出:

    调用两个参数的构造函数
  2. 初始化对象 bb: 使用Complex(double r, double i)构造函数,传入5.67.9作为参数,初始化对象 bb。输出:

    调用两个参数的构造函数
  3. 初始化对象 cc 通过拷贝构造函数: 使用拷贝构造函数Complex(Complex& c),以 aa 作为参数,初始化 cc,调用拷贝构造函数,使 cc 的成员变量的值与 aa 相同。输出:

    调用拷贝构造函数
  4. 打印对象 aacc 的值:调用print方法输出 aacc 的值。输出:

    a=(3,4)
    c=(3,4)
  5. 调用函数f:函数f接受一个Complex类型的参数。这里将对象 bb 传递给函数f。因为f的参数是按值传递的,所以这里会调用Complex(Complex& c)拷贝构造函数,创建 bb 的一个副本 nn ,然后在f中打印 nn 的值。输出:

    调用拷贝构造函数
    n=(5.6,7.9)
  6. 使用add方法:调用a.add(b),这里将对象 bb 传递给函数add。因为add的参数是按值传递的,所以这里会调用Complex(Complex& c)拷贝构造函数,输出:

    调用拷贝构造函数

    add方法内部,创建了一个名为 yy​ 的临时对象,用于存储相加后的结果。这一步调用了两个参数的构造函数Complex(double r, double i),输出:

    调用两个参数的构造函数
  7. add方法的返回值赋给对象 cc

  8. 打印c的值。输出:

    (8.6,11.9)

若将代码:

Complex Complex::add(Complex c)

改为:

Complex Complex::add(Complex & c); 

即使用引用传递。

此时输出:

调用两个参数的构造函数
调用拷贝构造函数
a=(3,4)
c=(3,4)
调用拷贝构造函数
n=(5.6,7.9)
调用两个参数的构造函数
(8.6,11.9)

可以看到通过引用传递可以避免创建参数的副本,不会触发Complex::Complex(Complex& c)拷贝构造函数,可以提高程序的效率。

亦可使用operator+来避免创建参数的副本。可将代码改为:

#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double r, double i);
Complex(const Complex& c); //将拷贝构造函数的参数更改为const引用
Complex add(Complex &c);
void print(void);
Complex operator+(const Complex& c);
private:
double real, image;
};
Complex::Complex(double r, double i) :real(r), image(i)
{
cout << "调用两个参数的构造函数" << endl;
}
Complex::Complex(const Complex& c)
{
real = c.real;
image = c.image;
cout << "调用拷贝构造函数" << endl;
}
void Complex::print(void)
{
cout << "(" << real << "," << image << ")" << endl;
}
Complex Complex::operator+(const Complex& c) { //将add方法更改为operator+
return Complex(real + c.real, image + c.image);
}
void f(Complex n)
{
cout << "n=";
n.print();
}

int main()
{
Complex a(3.0, 4.0), b(5.6, 7.9);
Complex c(a);
cout << "a=";
a.print();
cout << "c=";
c.print();
f(b);
c = a + b; //使用operator+
c.print();
}

输出结果与上面相同。

此外,这里的c = a + b;在c++11或优化的编译器中使用了移动赋值操作符operator=(Complex&&)赋值给c,但在老版本或者未优化的编译器中会调用拷贝赋值操作符,执行复制而占用空间。

要想实现日志效果,则可以在对象中添加operator=

拷贝赋值操作符:

Complex& operator=(const Complex& c) {
real = c.real;
image = c.image;
cout << "调用拷贝赋值操作符" << endl;
return *this;
}

移动赋值操作符:

Complex& operator=(Complex&& c) noexcept {
real = c.real;
image = c.image;
cout << "调用移动赋值操作符" << endl;
return *this;
}