类的定义
类(Class)其实和 C++ 结构体差不多。
1 | class ClassName |
public
,protected
,private
叫做段约束符
。private
和 protected
只允许类的内部成员访问。protect
和 private
在派生的地方不同。不写段约束符时,成员默认是 private
的。
三个段约束符的顺序可换;
可以把公开成员分开写,需要用多个 public
约束。
::
叫做作用域分辨符
。
类成员的定义、使用
和 struct
完全一样。.
,->
。略。
对了,以类声明的变量叫做 对象
(Object)。
静态数据成员
1 | class ClassName |
ClassName
的对象各自有成员 value
,但他们共同拥有成员 s_value
。
对于非常量的静态成员,必须在类内声明,类外定义(常量定义可以写在里面或外面)。
静态成员函数见后。
const 数据成员
const
数据一般是不可以被修改的,理应每个类的成员的值都一样,是可以共用以节省空间的。实际呢?
如果把一个数据设为 const
,他会自动变为 static
吗?
1 | class Test |
输出 00007FF64CC64034 00007FF64CC64038
。显然是没有共用的,必须加 static
才可以共用内存。
类类型本身、指针、引用作为函数参数
1 | void setTime(ClassName o); //类对象作为参数,会有拷贝构造函数 |
类的成员函数
这部分简单,不多说。
构造函数
在声明一个对象,或 new
一个对象的时候,会触发构造函数。
(注意 malloc
不会)
已经有的对象可以通过新建一个对象,然后赋值过去。
1 | CString A; |
一般构造函数
1 | class CString |
重载构造函数
1 | class CString |
定义函数要 {}
,就不用打 ;
了,声明函数要打 ;
。这不是 C 语言基础吗
拷贝构造函数
当使用 CString str2 = str1;
时,编译器实际上调用了默认的 CString(CString &)
拷贝构造函数,把 str1
的内容通过位拷贝,复制给了 str2
。
同时,拷贝构造函数也是将 const CString &
强转为 CString
的方法。
如果我们不想这么做,而是手动复制部分数据,可以使用:
1 | class CString |
注意 CString str2 = str1;
和 CString str2; str2 = str1;
是有区别的!!!
函数类型 | 函数原型 | 调用场景 |
---|---|---|
强制转换 | int () |
int(A); 和 int i = A; (隐式) |
拷贝构造函数 | CString(const CString &) |
CString B = A; 和 return A; |
赋值函数 | CString& operator = (const CString &) |
Cstring B; B = A; |
二者是不同的。
所以,重载拷贝构造函数的时候,要思考是否同时需要重载赋值函数。
类到其他类型的强制转换
既然提了把其他结构转为这个类的方法,那就顺便说说把这个类转为其他的结构吧。
把 int
当作一个一元操作符可还行。
1 | class teamS { |
析构函数
函数结束后,函数中声明的对象的内存会被释放,但对象申请的动态内存不会。
因此需要一个析构函数,这样,声明对象的函数运行完以后,即会执行析构函数,然后再释放对象的内存,最后退出函数。
1 | class CString |
以下场景会触发对象的析构函数:
- 声明对象的函数运行结束;
- 指向对象的指针被
delete
时。(free
不会)
这样以后,程序猿就不用再考虑什么时候对象不再使用,得释放内存了。
this 指针
在调用成员函数的时候,我们发现如果使用其他对象的成员需要加 对象->
,而使用自己的成员却不需要。
而调用不同对象的同一个成员时,编译器不会弄混用的是谁的成员。这是因为:编译器对成员函数隐含加上了 this
形参。
因此调用某对象的成员函数时,使用该对象的成员不需要加对象名和 ->
(也可以加 this->
)。
需要返回该对象(或该对象的引用)时,使用 *this
即可。
静态成员函数
静态成员函数与众不同的地方在于,它没有 this
参数。声明仅仅是在返回类型前加了一个 static
。
1 | class CString |
友元函数 友元类
对于某些需要封装过的数据的函数,调用这些数据不大容易。因此,产生了友元的机制。
友元函数是让类外的函数可以访问到类的 private 成员;
友元类是让类下的所有函数可以访问前一个类里的 private 成员。
注意友元函数是类外的函数,因此没有 *this
参数,且不用 ClassName::
作用域符。(不过定义部分还是可以写在声明后面)
1 | class Y; //前向声明 |
友元类没有对称性、传递性。
友元函数虽然方便,但是破坏了 OOP 的封装性,不能滥用。
类的组合
一句话,就是一个类的某个成员是另一个类的对象。
注意构造函数和析构函数一般需要调用包含的类的构造和析构函数,否则无法修改前一个类的 private
成员。
具体语法如下:
1 | class Point{ |
const 对象、函数
一句话,const 对象不能被非 const 的成员函数调用。
1 | const CString str; //常对象 |