课程记录一(侯捷C++高级编程)

技术栈杂食者
• 阅读 2209

在本章主要简述定义一个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;
};

调用该函数的结果为:
课程记录一(侯捷C++高级编程)
所以在传值得时候创建了一个局部对象,使用复制构造函数度这个局部变量进行了初始化,在离开作用域的时候会销毁这个局部变量,因此会调用析构函数,这也太麻烦了。

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

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

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

调用方式为:

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

结果为:
课程记录一(侯捷C++高级编程)
两次调用了析构函数与复制构造函数,原因在于首先在传递参数的时候在函数内部构造了一个局部对象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中竟然可以访问!我们可不可以通过继承一个类来访问其私有数据来打破封装性呢?很明显不行,因为私有数据不被继承(这句话不一定对,因为子内存上还是继承了只是不能直接访问而已)。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
java成员变量的初始化
类变量(static变量,不需要实例化对象也可以引用)实例变量(非static变量,需要实例化对象)局部变量(类的成员函数中的变量)初始化方式:构造函数初始化变量声明时初始化代码块初始化java自动初始化(在构造函数执行之前执行) java保证所有变量被使用之前都是经过初始化的(声明并且定义过,被赋值
Wesley13 Wesley13
3年前
java第二次作业
(一)学习总结1.什么是构造方法?什么是构造方法的重载?下面的程序是否可以通过编译?为什么?(1)在对面向对象程序中构造方法的主要作用是为类中的属性初始化。在构造方法中要注意以下几点①构造方法的名称必须与类名称一致②构造方法的声明处不能有任何返回值类型的说明③不能在构造方法中使用return返回一个值(2)构造方法的重载就
Wesley13 Wesley13
3年前
IOS全局变量
IOS中的全局变量和JAVA中的全局变量定义和使用方法不一样,在Java中,只需要将变量定义为static就行了。而在IOS中这种方法不适合。IOS中定义全局变量有三种方法:1.使用extern关键字在AppDelegate.m或AppDelegate.h中写入你需要的全局变量名,例如:int name;注意定义全局变量时候不能初始化,否则报错
Wesley13 Wesley13
3年前
Java中的native关键字
一. 什么是NativeMethod  简单地讲,一个NativeMethod就是一个java调用非java代码的接口。一个NativeMethod是这样一个java的方法:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern"C"告知C++编译器去
Wesley13 Wesley13
3年前
HTTP面试题(二):HTTP请求报文和响应报文格式
!(https://oscimg.oschina.net/oscnet/0406894fb1274bee91fc53c84c516576.jpg)看都看了还不点个赞!(https://oscimg.oschina.net/oscnet/095d444dc9a449ee85afd19b00fdf52b.png)!(h
Stella981 Stella981
3年前
Duang,HUAWEI DevEco IDE全面升级啦
想感受全新UI带来的视觉及交互体验、HiKey970开发板调测、HiAIAPI推荐和收藏、深度AI模型分析等新功能,体验高清晰度和流畅度的远程AI真机调测吗?!(https://oscimg.oschina.net/oscnet/f4e1bb24ff00b8c6ea27f75370a53bfbacd.jpg)全新的UI设计
Wesley13 Wesley13
3年前
C++中初始化的顺序问题
C的初始化顺序非常重要,牢记才能不出常识性的错误。其初始化顺序为:1类中的static成员是最先初始化的,这个是先于main函数的执行的,但是必须注意,如果这个成员只是在类中声明,而没有在类外边进行定义的话,那么这个是不会开辟内存的,是不会初始化的。2调用基类的构造函数。但是基类分为两种顺序,特别注意。一种是虚继承的基类;另一种是普通继承
Stella981 Stella981
3年前
Boost Python官方样例(三)
导出C类(纯虚函数和虚函数)大致做法就是为class写一个warp,通过get\_override方法检测虚函数是否被重载了,如果被重载了调用重载函数,否则调用自身实现,最后导出的时候直接导出warp类,但是类名使用class,析构函数不需要导出,因为它会被自动调用纯虚函数编写C函
美凌格栋栋酱 美凌格栋栋酱
4个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(