乐趣区

课程记录一侯捷C高级编程

在本章主要简述定义一个 C ++ 类的时候需要注意的细节,包括初始化列、操作符重载等。
实例讲解代码为:

#ifndef COMPLEX_H
#define COMPLEX_H
#include<iostream>
using std::ostream;
using std::endl;
using std::cin;
using std::ends;
using std::cout;
class Complex
{
public:
    Complex(double, double);
    Complex(const Complex&);
    ~Complex();
    double Get_re()const;
    double Get_img()const;
    Complex& operator +=(const Complex &);
private:
    double re;
    double img;
    friend Complex& _add(Complex*, const Complex&);// 由于需要去除 private 元素,所以这设置为友元, 在调用一个函数的友元的时候,其也具备访问另一个对象 private 的能力
};

inline Complex::Complex(double re = 0, double img = 0) :re(re), img(img)
{
};
inline Complex::Complex(const Complex & comp) 
{
    this->re = comp.re;
    this->img = comp.img;
    cout << "调用了复制构造函数" << ends;
}
inline Complex::~Complex()
{cout << "析构函数被调用" << endl;};
inline double Complex::Get_re() const
{return re;};
inline double Complex::Get_img() const
{return img;};
inline Complex& _add(Complex* ths, const Complex& plus_ele)
{
    ths->re += plus_ele.re;
    ths->img += plus_ele.img;
    return(*ths);
}
// 下面是包含 this 的重载运算符
inline Complex& Complex::operator +=(const Complex& plus_ele)
{return _add(this, plus_ele);
}
// 下面的都是不包含 this 的重载运算符
inline Complex operator +(const Complex & comp1, const Complex & comp2)
{return Complex(comp1.Get_re() + comp2.Get_re(), comp1.Get_img() + comp2.Get_img());
}
inline ostream& operator <<(ostream& os, const Complex& comp)// 主要是为了应对连续使用 << 的情况
{return os << comp.Get_re() << "+" << comp.Get_img()<<"i";}
inline void test_reference(Complex com)
{cout << com << ends;}
#endif // !COMPLEX_H

1、构造一个类的相关建议:

1、成员数据一定放在 private;

主要是为了防止通过对象直接更改内部的值,当然可以通过成员函数来更改其中的值,目的是增加类的封装性。

2、参数最好以引用来传;

如果使用一个值来传递的化我们可以定义一个全局函数接受一个 Complex 为入口参数:

inline void test_reference(Complex com)
{cout << com << ends;}

同时在析构函数加入:

inline Complex::~Complex()
{cout << "析构函数被调用" << endl;};

调用该函数的结果为:

所以在传值得时候创建了一个局部对象,使用复制构造函数度这个局部变量进行了初始化,在离开作用域的时候会销毁这个局部变量,因此会调用析构函数,这也太麻烦了。

3、返回值最好使用引用;

主要原因在于如果返回的是一个对象的话,这个对象是也是个临时对象,将会在调用该函数的那一行后被析构。我们加入一行

inline Complex test_reference1(Complex com) 
{return com;}

调用方式为:

    Complex cmp1(1, 2);
    Complex cmp2(1,1);
    cmp2=test_reference1(cmp1);

结果为:

两次调用了析构函数与复制构造函数,原因在于首先在传递参数的时候在函数内部构造了一个局部对象 com,在返回一个对象后悔临时再构建一个对象用于给 cmp2 赋值,随后到下一行这个临时变量就被析构函数析构了。

4、在类的主体类中成员要加 const 最好要加;

没啥好说的,就是为了防止在局部函数中更改了原始数据,如果确实有这个需求除外。

5、构造函数最好要是有初始化列表;

初始化列表初始化对象中的变量的作用是避免了初始化内部对象 + 赋值的操作,如果使用的是初始化列表,那么其使用的是复制构造函数,这样节省了大量的时间。

6、需要注意操作符重载;

在进行操作符重载的时候可以分为两类
1、包含 this 的成员函数(成员);
2、不包含 this 的非成员函数(全局);
这样区别的理由是这个操作符的对象结果是否又被赋值给了这个操作符的入口参数?如果被赋值的对象为入口参数变量如 +=,-= 等,那么这个操作符重载应该是类的成员函数,例如 cmp1+=cmp2 的时候左侧 cmp1 既是入口参数也是被赋值的对象,因此这个操作符应该被定义为成员函数。如果这个操作符的结果并未赋值给入口参数变量,那么应当定义为全局运算符重载,如—,+ 等。

7、相同类的 class 的各个 objects 互为友元(friends)

也就是说在一个对象处理另一个类的 private 数据时候是有权限的:

inline double Complex::get_sum(const Complex& comp)const 
{return this->re + comp.re;};

comp.re 是对象 comp 的 private 数据但是在 this 中竟然可以访问!我们可不可以通过继承一个类来访问其私有数据来打破封装性呢?很明显不行,因为私有数据不被继承(这句话不一定对,因为子内存上还是继承了只是不能直接访问而已)。

退出移动版