小古银的官方网站(完整教程):http://www.xiaoguyin.com/
C++入门教程视频:https://www.bilibili.com/video/av20868986/
目录
现在讲的是面向对象的特性之一:继承。继承又叫派生。
基础示例
#include <iostream>
#include <string>
// 创建一个新的类u32stringex, 它继承自std::u32string
// 那么u32stringex类就会将std::u32string所有public和protected的成员都继承下来
// 也就是说, 类u32stringex拥有std::u32string所有的public和protected的成员
class u32stringex : public std::u32string
{
};
int main(void)
{
// 创建一个字符串对象text
u32stringex text;
// 对象text可以使用std::u32string的公共成员函数empty
std::cout << std::boolalpha << text.empty() << std::endl;
return 0;
}
输出结果:
true
基础讲解
首先定义一个类叫u32stringex
,然后让它继承标准库字符串类std::u32string
,那么代码就是如下:
class u32stringex : public std::u32string
{
};
u32stringex
叫做子类,对应std::u32string
则叫做父类;u32stringex
也可以叫做派生类,对应的std::u32string
则叫做基类。
使用继承以后,在类u32stringex
中虽然没有把代码明确写出来,但是它默认就拥有了类std::u32string
的所有public
和protected
的成员。所以使用类u32stringex
声明了一个对象text
,这个text
就可以使用std::u32string
的public
成员函数empty
。而按照规定,父类的private
成员能够被继承到子类中但是子类不能访问这些私有成员。
注意:基类的所有成员都会被继承到派生类中,除了构造函数和析构函数。
巩固练习
继承相关的练习题在后面异常中进行练习,现在需要对simple_vector
进行优化。
我们的这种设计每新增一个就会多一份内存,而删除一个元素就会减少一份内存,这样就不会耗费多余的内存。然而,现在几乎所有的程序需要的数据都是非常大量的,如果用这个simple_vector
来保存数据时,你会发现,第1次复制0个数据赋值1个新数据,第2次复制1个数据赋值1个新数据,第3次复制2个数据赋值1个新数据,第4次复制3个数据赋值1个新数据,第n次复制n-1个数据赋值1个新数据,也就是说第n次添加新数据时都会赋值n份数据。而大多数情况下,都是一次过读进很多数据,假设我一次过读入十万个数据,那么就会赋值1*2*3*4*5*6*…*100000,就是赋值十万的阶乘,估计这时候你的程序就会卡在那里很久直到数据复制完成。
解决这种情况,可以在构造的时候就申请一个很大很大的内存空间,那么新增数据基本上就不需要重新赋值了,直接把新数据添加到最后即可,速度非常快,但是如果我创建一个simple_vector
对象只保存10个数据,这样的话剩下的那么大的内存就很浪费了,而且程序中可能也会有几千几万个simple_vector
对象,每个都这么大的内存,操作系统没这么多内存来运行也会卡死。
所以只能采用折中的方法,第一次添加就申请一小段内存,然后添加几个数据就不需要重新赋值了,然后当这段内存用完之后再添加新数据时,再申请一个更大的内存(一般是原来2倍大小),然后再重新赋值,再把新数据添加进去,接着后面的几次添加数据都不用重新赋值了。当再次使用完这段内存时又是同样的操作。这就是std::vector
内部的实现方法。
那么现在看一下需要看一下什么地方需要变动:
由于实现方法改变了,元素的数量和申请的内存数量不是一致的,所以需要添加新的成员变量
m_capacity
,它保存内存的实际数量,而m_size
的含义改成元素的数量。然后需要改变
push_back()
的实现。当m_capacity
等于0时,即没有内存的时候,申请1份内存空间,然后对保存新数据并且对成员变量做相应修改,这里的判断要用m_capacity
而不是m_size
,因为有内存的情况下可以没有元素。接着在添加数据前,当元素数量和内存数量相等的时候,即没有剩余内存的时候,就需要申请新的内存,而申请的新内存数量每次都是旧内存的2倍,然后复制旧数据。然后就是添加新数据并且更新元素数量。pop_back()
:删除最后一个元素只需要将元素数量减1即可,那么只需要在类的他成员中保证做到不会访问到不应该访问的地方就可以了。接着是
insert()
,由于连续内存的特性,在中间插入和删除对需要赋值,这是改变不了的事实,不过,不重新分配内存可以减少一点复制量,而且再越后的地方插入,复制量越少。当不需要重新分配内存时,应该从最后一个元素开始,后一个位置复制前一个位置的数据。erase()
:比较简单就不进行提示讲解了。clear()
:当一开始没有内存空间时,m_size = 0;
不会发生任何实质的改变;当有内存而没有元素时,也不会发生任何实质的改变;当有元素时,m_size = 0;
而不改变m_array
和m_capacity
的值,也是符合整体设计的。所以可以直接用m_size = 0;
。
当我们改完之后,还需要看一遍类中其他成员函数还有没有漏掉没改的,只要有一个成员函数有错误,那么很有可能导致其他没错的成员函数也会出现不正常的情况。
当完成上面的修改后,simple_vector
就算是比较完美了。