最近留校闲暇无事,又看了一些关于C++的教程,感觉收获颇丰。

主要是关于C++中OOP机制,其实对于其他OOP语言也是适用的。

先给大家推荐相应的教程:

##OOP之封装

对象在内存中的存储

这一块真的很重要啊!!!一直想了解不同代码在内存中的存储,现在终于把它搞清楚了。(多说一句:北航夏令营面试的时候问的都是多态的知识。。。)

内存中按照用途划分的五个区域:

  • 1、栈区:变量存储的位置;内存由系统分类、回收。

  • 2、堆区:当我们new、delete一个对象时,就是在堆区进行操作。堆区的内存有程序员来申请创建、回收

  • 3、全局区:存储全局变量、静态变量

  • 4、常量区:存储常量

  • 5、代码区:存储逻辑二进制代码

带有初始化列表的构造函数

因为有了封装,因此我们需要一个相对简单的方法来实现构造函数对类变量的初始化。而带有初始化列表的构造函数与普通构造函数的区别在于:

  • 带有初始化列表的构造函数可以用来对const类型变量进行初始化

  • 带有初始化列表的构造函数相对于一般构造函数速度上要快一些

拷贝构造函数

拷贝构造函数作为使用拷贝赋值方式产生新对象的构造函数

例如:

假设我们有类Student;则如下代码使用默认构造函数对stu1进行初始化,而使用拷贝构造函数对stu2初始化。

1
2
Student stu1;
Student stu2(stu1);

当采用直接初始化或复制初始化时,系统自动调用拷贝构造函数。

如果程序员没有定义拷贝构造函数,则当需要适用拷贝构造函数时,由系统自动生成。

拷贝构造函数定义形式与一般构造函数很相似,形式如下:

Student(const Student& stu);

析构函数

既然提到了构造函数,那么同new与delete运算符的关系一样,我们还有析构函数以供对象调用完毕后的善后工作。

对于以下这个类:

1
2
3
4
5
6
class Student {
public:
Student() { m_pName = new char[20]; }
private:
char *m_pName;
};

析构函数的作用就在于处理对象使用结束后的善后工作,比如这里回收m_pName开辟的空间。

如果没有自定义的析构函数,则由系统自动生成。

析构函数在对象销毁时自动调用。

析构函数没有返回值、没有参数,因此也不可以重载。

对象的生命历程:
申请内存->初始化列表->执行构造函数->对象参与运算->执行析构函数->释放内存

类由成员函数、数据成员组成,可限定命名空间,确保其唯一性。

类的成员函数中除析构函数外都可以重载

对象的实例化可分为栈中实例化与堆中实例化

前面提到过,栈中实例化即直接定义对象,而堆中实例化则是使用new操作符申请空间创建的对象实例化过程

变量初始化可分为复制初始化与直接初始化,其中直接初始化是C++在C的基础上的改进

复制初始化形如:int x = 12;

直接初始化形如:int x(12)

引用

引用可以直接理解为别名

指针类型的引用,举个栗子:

1
2
3
int a = 10;
int *p = &a;
int *&q = p;

引用作为函数参数,举个栗子交换两int变量值的函数:

1
2
3
4
5
6
7
8
9
void fun(int *a, int *b) {
int c = 0;
c = *a;
*a = *b;
*b = c;
}
int x = 10, y = 20;
fun(&x, &y);

或者:

1
2
3
4
5
6
7
8
9
void fun(int &a, int &b) {
int c = 0;
c = a;
a = b;
b = c;
}
int x = 10, y = 20;
fun(x, y);

C++ 中的内存管理

使用new运算符来申请内存,使用delete运算符来释放一段内存。

注意:

申请释放一段内存形式如下:

1
2
int *arr = new int[10];
delete []arr;

一般我们申请内存后需要判断是否申请成功,而释放内存后也需要把指针设为空指针

对象成员、深拷贝、浅拷贝与const

对象成员是指一个类中有其他类成员。

比如我们定义了一个线段Line类,那么这个线段可以包含两个点Point类。

当我们实例化对象A时,如果对象A有对象成员B,那么先执行对象B的构造函数,再执行A的构造函数。

类似与FILO原则,当我们销毁对象A时,先执行对象A的析构函数,再执行B的析构函数

如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B

深拷贝与浅拷贝

对于如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Array {
public:
Array() { m_iCount = 5; m_pArr = new int[m_iCount]; }
Array(const Array& arr) { m_iCount = arr.m_iCount; m_pArr = arr.m_pArr; }
private:
int m_iCount;
int *m_pArr;
};
int main() {
Array arr1;
Array arr2 = arr1;
return 0;
}

这是一个浅拷贝的例子,执行代码后,对象arr1、arr2的m_pArr指向同一块内存,这就不适用于我们想要实现真正意义上的复制的情况。

而深拷贝其实很简单,就是我们在拷贝函数中实现深度拷贝,栗子如下:

>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Array {
public:
Array() {m_iCount = 5;}
Array(const Array& arr) {
m_iCount = arr.m_iCount;
m_pArr = new int[m_iCount];
for(int i=0; i<m_iCount; ++i) {
m_pArr[i] = arr.m_pArr[i];
}
}
private:
int m_iCount;
int *m_pArr;
};
int main() {
Array arr1;
Array arr2 = arr1;
return 0;
}

C++ OOP特性还可参考本站其他相关博文:

C++ 【oop】继承篇

C++ 【oop】多态篇

C++ 【oop】模板篇