设计C++ 类应该注意的事项
- 为了避免头文件的重复加载,应该写成下面的形式——防卫式声明
头文件中一般都放一些函数、类等的声明
#ifndef __TEST__
#define __TEST__
#endif
- include调用自定义的库,用<>,标准库用“”
- inline修饰函数——对编译器建议,将哪些函数作为inline(类似于宏,理解为在编译的时候可以替换,加快代码的效率),但是是否真的用做为inline由编译器决定
- access level
- private——尽量将类的数据放在其中可以保护变量
- public——一般函数放在其中
- friend——打开了封装的大门
- 类的构造函数,最好用其独特的优秀的 列表形式进行初始化!效率更高一些
class Test{
public:
Test (double x, double y) // 列表形式构造函数
: in_x (x),in_y(y)
{}
private:
double in_x,in_y;
}
-
函数的重载 overload——虽然从读者的角度,函数是一样的,但是在编译器看来因为参数的不同,两个函数是不一样的
-
在构建函数的时候,注意用const修饰
void function1() const { xxxxxx};
- 函数中的数据可以更改
- 不可以被更改
-
函数参数的传递形式——好的习惯应该在设计时就考虑,变量的大小、是否会被修改等
- pass by value 【整个赋值,数据有多大就压缩多大到函数的堆栈中】
- pass by reference,用&修饰【传递参数的别名,只是一个地址 4个字节】
- pass by reference to const 【希望传递的值为只读,不希望被修改可以用const修饰】
-
返回值的传递 需要判断原来的是不是local object
如果是local obeject 则不能返回引用,什么是local object呢?以赋值为例,如果待放入的对象(返回的对象)本来就存在,不是函数的局部变量,就可以用引用的方式进行返回。- by value
- by reference
-
类中特殊的几个函数
- 构造函数——没有返回类型
- 拷贝构造函数 如果传入的是指针,则应该用拷贝构造而不是普通的构造/赋值
- 拷贝赋值
inline String& String::operator=(const String& str) { if (this == &str) return *this; // 高级写法,赋值的时候可以先做一个self assignment 提高效率!确保正确性(避免传入元素和待赋值元素指向同一份空间,后者释放之后容易为空)! delete[] m_data; // 1.先释放出原来的空间 m_data = new char[ strlen(str.len(str.m_data) + 1)]; // 2.创建出和传入元素一样大的空间 strcpy(m_data, str.m_data); // 3.将传入元素一对一的赋值过去 return *this }
- 析构函数——以~开头的函数
在离开对应作用域的时候,会自动调用该函数——释放出对应的空间/内存
注意——{ }包含的地方为一个作用域。不仅是在函数、类、结构体中用,在main函数里面也可以嵌套,但是需要确保对应的变量之后不会再用到(释放之后就没有了) - 构造函数——没有返回类型
浅拷贝 vs 深拷贝
- 浅拷贝 ——只是拷贝指针,有可能造成内存泄漏
- 深拷贝 —— eg:将指针指向的所有元素一对一的进行copy
stack && heap
- stack
以{ }为间隔表示一个scope(eg 普通函数、main函数),类在离开自己的scope的时候,会自动调用析构函数释放用到的空间。
如果变量用static修饰,表示该变量是静态的,离开scope之后不会被清除,程序运行结束之后,才释放空间。
- heap
在内存中,user主动的利用new在内存中去开辟一段空间,该空间需要user手动去释放,否则,即使程序运行结束(离开main),对应的内存还是被占用(内存是有限的!)
new做了什么?
- 分配内存——重定向c中的mallloc
- 转型
- 调用构造函数
delete做了什么?
- 调用析构函数
- 释放内存——重定向c中的free