C++动态数组类的封装实例动态数组类的封装实例
C++中的动态数组(Dynamic Array)是指动态分配的、可以根据需求动态增长占用内存的数组。为了实现一个动态数组类的
封装,我们需要考虑几个问题:new/delete的使用、内存分配策略、类的四大函数(构造函数、拷贝构造函数、拷贝赋值运算
符、析构函数)、运算符的重载。涉及到的知识点很多,对此本文只做简单的介绍。
一、内存分配策略一、内存分配策略
当用new为一个动态数组申请一块内存时,数组中的元素是连续存储的,例如 vector和string。当向一个动态数组添加元素
时,如果没有空间容纳新元素,不可能简单地将新元素添加到内存中的其他位置——因为元素必须连续存储。所以必须重新分
配一块更大的内存空间,将原来的元素从旧位置移动到新空间中,然后添加新元素,释放旧的内存空间。如果我们每添加一个
新元素,就执行一次这样的内存分配和释放操作,效率将会慢到不行。
为了避免上述的代价,必须减少内存重新分配的次数。所以我们采取的策略是:在不得不分配新的内存空间时,分配比新的空在不得不分配新的内存空间时,分配比新的空
间需求更大的内存空间(通常为间需求更大的内存空间(通常为2倍)。这样,在相当一段时间内,添加元素时就不用重新申请内存空间倍)。这样,在相当一段时间内,添加元素时就不用重新申请内存空间。注意,只有当迫不
得已时才可以分配新的内存空间。
二、类的四大函数二、类的四大函数
一个C++类一般至少有四大函数,即构造函数、拷贝构造函数、拷贝赋值运算符、析构函数。如果类未自己定义上述函
数,C++编译器将为其合成4个默认的版本。但是往往编译器合成的并不是我们所期望的,为此我们有必要自己定义它们。
1.构造函数构造函数
类的构造函数(constructor)用来初始化类对象的非static数据成员,无论何时只要类的对象被创建,就会执行构造函数。
class Foo {
public:
Foo(); // 构造函数
Foo(string &s);
// ...
};
构造函数的名字和类名相同,没有返回类型。类可以包含多个构造函数(重载),它们之间在参数数量或类型上需要有所区
别。构造函数有一个初始化部分和一个函数体,成员的初始化是在函数体执行之前完成的。
2.拷贝构造函数拷贝构造函数
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数(copy
constructor)。
class Foo {
public:
Foo();
Foo(const Foo&); // 拷贝构造函数
// ...
};
拷贝构造函数定义了如何用一个对象初始化另一个同类型的对象。拷贝初始化通常使用拷贝构造函数来完成。拷贝初始化发生
在下列情况中:
使用等号(=)初始化一个变量
将一个对象作为实参传递给一个非引用类型的形参
从一个返回类型为非引用类型的函数返回一个对象
用花括号列表初始化一个数组中的元素
3.拷贝赋值运算符拷贝赋值运算符
类的拷贝赋值运算符(copy-assignment operator)是一个名为operator=的函数。类似于其他任何函数,它也有一个返回类型
和一个参数列表。
class Foo {
public:
Foo();
Foo& operator=(const Foo&); // 赋值运算符
// ...
};
拷贝赋值运算符定义了如何将一个对象赋值给另一个同类型的对象。赋值运算符是一个成员函数也是一个二元运算符,其左侧
运算对象就绑定到隐式的this指针,右侧运算对象作为显式参数传递。注意:为了与内置类型的赋值保持一致,赋值运算符通
评论0