C++全面精通类与对象

 更新时间:2022年05月27日 11:43:17   作者:乔乔家的龙龙  
类和对象是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型;变量就是可以变化的量,存储在内存中—个可以拥有在某个范围内的可变存储区域

运算符重载

C++语法设计很巧妙,比如运算符重载一个 >

bool operator>(const Date& d)
{
     return !(*this <= d);
}

这里可以结合前面的内联函数来进一步提高代码的效率,而内联函数不支持 .h 和 .cpp 分开写,所以成员函数要成为内联函数最好的办法就是把定义放在类里面,类里面定义的会被默认为是 inline 内联函数。

我们计算日期类的加法时:

	Date Date::operator+(int d)
	{
		Date ret(*this);
		ret.day += d;
		while (ret.day > Getmonth(ret.year, ret.month))
		{
			ret.day -= Getmonth(ret.year,ret.month);
			ret.month++;
			if (ret.month == 13)
			{
				ret.year += 1;
				ret.month = 1;
			}
		}
		return ret;
	}

运算符复用

我们可能会有这样的问题,这里面 += 和 + 两个运算符其实是一样的,实现原理上没什么差别,那你可能会封装个函数来解决他们的关系,但是其实直接让他俩互相附庸,分为了 += 复用+ 和 + 复用 += 两种办法:

1.+= 复用 +:

2.+ 复用 +=(更优):

两种乍一看其实没什么区别,但是其实有优越和劣势可以分的,很 += 是不需要构造的,因为它是传引用调用(返回值为域外的 this 指针的内容,必须要传引用),但是 + 是必须要构造的,拷贝局部对象的 ret 和 最后的 return , 一共需要构造两次。

让 += 复用 +,+在先就会让整个过程构造 4 次,而让 + 来复用 += 的话,+ 还是构造 2 次没得说,但是 += 就不需要拷贝构造了,整个过程就只需要构造 2 次,消耗就会小很多。咱就应该多抠抠细节,写出正确的代码固然重要,但是追求更优秀更高效的代码是每一个程序员的基本素养。

前置后置运算符

既然 +,- 能造,那 ++ 和 – 自然也不在话下,但是这就不好玩了啊, num++ 和 ++num 功能上都是 +1,写成运算符重载格式都是

Date Date::operator++();

我们该怎么区分呢?要知道函数名相同而参数不同就应该敏感使用函数重载,C++这个大聪明是不会考虑不到这些的,因此就有了对应的语法:前置不带参数而后置带参数

Date operator++();//前置++

Date operator++(int d);//后置++

Date& operator++()//前置
{
   *this += 1;
   return *this;
}
Date operator++(int)//后置
{
    Date tmp(*this);
    *this += 1;
    return tem;
}

其实括号里面这个参数并没有任何意义,单纯只是用来区分前置与后置的写法,所以这里不写形参也是可以的,我这里就只给了一个类型。还有这里千万不要想着去加一个缺省值,显式传参还好,要是不传参编译器就没办法区分开来,属于是没事找事了。

const

给一个场景:

void Func(const Date& d)

{

d1.Print();

}

void test()

{

Date d1(2022,5,19);

d1.Print();

Func(d1);

}

这个场景下就会报错:

说实在的,这个报错我自己也看的云里雾里,为什么 Print 那里不报错到了 Func 里面 Print 就要报错?Print 传的过去 Func 就传不过去了?究其为什么会报错,其实涉及到一个权限问题。

void Print(Date* const this)
{
     cout<<year<<"-"<<month<<"-"<<day<<endl;
}

我们知道 Print() 的参数其实是 Date& const this ,在上面场景中去调用 Print 时其实参数是 &d1,传对象的地址。在 Print 定义时 const 修饰的是 this 指针,const 修饰的变量可以初始化,此时指针不能被改变但是他指向的内容可以被初始化和修改;而 Func 的 const 修饰 Date*,他指向的内容不能被修改,所以这是一个经典的权限放大问题。

const Date* 要传给 Date* ,所以我们需要一个 const 进行修饰保护,但是 this 本质是一个隐含形参,我们没办法显式调用,也就是说 const 没办法进行修饰。那么C++也提供了一种修饰方法打破这个僵局,就是在函数尾巴加上 const。

void Print() const
{}

尾巴上的 const 编译器就会默认你是加在了函数原本定义的前面,这样就完美了。

C++ 的IO流

我们在代码中使用的 << , >> 为流输入和流提取操作符,只要涉及输入或者输出数据,我们立马想到的就是 cin 和 cout,这俩货其实是全局的对象, cin 对应 istream 类,cout 对应 ostream 类,它们都声明在 头文件中,这也解释了“为什么在 C++ 程序中引入 就可以使用 cin 和 cout”。

我们之所以可以在 <<, >> 之后接上任何类型,是因为强大的语法对每种类型进行了重载,能自动识别类型的本质就是函数重载,所以如果一个 int 类型的流插入 cin<<1 其实是 cin . operator <<(1)。

初始化列表

与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段,初始化列表可以看成是对象的成员变量定义的地方:

class Func
{
public:
    Func(int a):
    _a(a){} // 初始化列表
private:
    int _a;
};

注意:每个成员变量在初始化列表中只能出现一次因为初始化只能初始化一次,还要明确哪些成员必须放在初始化列表进行初始化:

  1. 引用成员变量
  2. const 成员变量
  3. 自义定类型成员(该类没有默认构造函数)

其他变量即可以在初始化列表初始化也可以在函数体内初始化,内置类型成员不处理时,会调用默认构造函数即随机值,如果我给出缺省值,那么之这个值就是给初始化列表用的,如果在初始化列表也同时给出这个内置类型的初始化值,就会采用初始化列表的值。我们应该尽量在初始化列表就初始化完,这样能尽可能的减少很多毛病效率也高。

再来看看这个题目:

这个程序的结果是啥?

答案是 1 和随机值,因为成员变量在类中的声明次序就是他在初始化列表中的初始化顺序,与他在初始化列表中的先后次序无关。_a2 先声明 _a2 = _a1,此时 _a1 为随机值,所以 _a2 为随机值,_a1 为 1。

explicit 关键字

构造函数不仅可以构造和初始化对象,对于单个参数的构造函数,还具有类型转换的作用。在C语言里面我们就知道有隐式类型转换,其实在 C++ 里面也是一样的,比如针对我定义的一个 Date(int year):

Date d1(2022);
Date d2 = 2022;

显然, 这里 d2 需要的是 Date 类型的参数, 而我们传入的是一个int, 这个程序却能成功运行, 就是因为这隐式调用,另外说一句, 在对象刚刚定义时, 即使使用的是赋值操作符 = , 也是会调用构造函数, 而不是重载的 operator= 运算符。这两个语句对应前者是构造,而后者是构造+拷贝构造,相当于发生了隐式类型转换, 如果我们写成:

explicit Date(int year)

这个关键字会阻止这种转换的发生。

到此这篇关于C++全面精通类与对象的文章就介绍到这了,更多相关C++类与对象内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • VS中动态库的创建和调用方式详解

    VS中动态库的创建和调用方式详解

    库的存在形式本质上来说库是一种可执行代码的二进制,​ 静态库和动态库的区别主要是在链接阶段处理库的方式不同而区分的,本文介绍VS中动态库的创建和调用方式,感兴趣的朋友一起看看吧
    2024-01-01
  • C++解密Chrome80版本数据库的方法示例代码

    C++解密Chrome80版本数据库的方法示例代码

    这篇文章主要介绍了C++解密Chrome80版本数据库的方法示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • C++实现LeetCode(121.买卖股票的最佳时间)

    C++实现LeetCode(121.买卖股票的最佳时间)

    这篇文章主要介绍了C++实现LeetCode(121.买卖股票的最佳时间),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言项目爬楼梯的两种实现方法参考

    C语言项目爬楼梯的两种实现方法参考

    今天小编就为大家分享一篇关于C语言项目爬楼梯的两种实现方法参考,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • 对C语言编程标准以及声明的基本理解

    对C语言编程标准以及声明的基本理解

    这篇文章主要介绍了对C语言编程标准以及声明的基本理解,有助于对C语言编写时的结构有更加清晰的认识,需要的朋友可以参考下
    2015-11-11
  • C++中访问权限的示例详解

    C++中访问权限的示例详解

    C++通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限(也称为可见性),下面这篇文章主要给大家介绍了关于C++中访问权限的相关资料,需要的朋友可以参考下
    2021-07-07
  • 基于Qt实现离线瓦片地图下载器

    基于Qt实现离线瓦片地图下载器

    这篇文章主要介绍了如何通过Qt实现离线瓦片地图下载器,文中的示例代码对我们学习或工作有一定的帮助,感兴趣的可以跟随小编一起学习一下
    2022-01-01
  • C语言三子棋一步步实现详程

    C语言三子棋一步步实现详程

    三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了,想用c语言做出这个游戏,事实上也是比较简单的,下面通过c语言进行对五子棋的分析
    2022-02-02
  • C语言中递归和排列组合详解

    C语言中递归和排列组合详解

    大家好,本篇文章主要讲的是C语言中递归和排列组合详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • C++智能指针之shared_ptr的具体使用

    C++智能指针之shared_ptr的具体使用

    本文主要介绍了C++智能指针之shared_ptr的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2022-05-05

最新评论