C++ class学习笔记

C艹速成笔记,不要看,没网上写得好!

起因是dbh问了我一个问题,忽然想起到自己不会C艹QAQ

成员函数

类中的成员可以是变量也可以是函数。

成员函数又两种定义的方式,一种是在class里直接定义,一种是在class外用范围解析运算符 :: 定义。

1
2
3
4
5
6
7
8
9
10
11
12
class Box
{
public:
double length; // 长度
double breadth; // 宽度
double height; // 高度

double getVolume(void)
{
return length * breadth * height;
}
};

也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Box
{
public:
double length; // 长度
double breadth; // 宽度
double height; // 高度

double getVolume(void); // 成员函数声明
};
// 成员函数定义
double Box::getVolume(void)
{
return length * breadth * height;
}

后面的构造函数也有这两种定义方式。

访问修饰符 Access modifiers

C++通过 public、private、protected 来标记成员的访问类型(没有标记默认为private

  • public 成员:在类的外部可以访问,可以通过类的名称. 成员名称访问。
  • private 成员:在类的外部不可访问,只有类里的函数和友元函数可以访问。
  • protect 成员:与 private 非常相似,但有一点不同,protected 成员在派生类(即子类)中是可访问的。

继承(派生类) Inheritance

派生类顾名思义,就是从一个类或多个(基类super-class)中派生出来的类(废话

课件里的这张图非常清晰地体现出了继承的结果,直接放图了。。(侵删

课件里画了多继承,但是没讲。。。

多继承 Multiple Inheritance

有很多种多继承 多继承的关系形成一张拓扑图

树形的继承关系还好理解,但是如果一个类从两个基类中继承过来就会有一些问题。就是如果两个基类中有相同的函数名/变量名如何区分?详见这篇文章 C++中类的多继承

构造函数 Constructor & 析构函数 Destructor

类的构造函数是类的一种特殊的成员函数,在每次创建类的新对象时执行。

如果我们没有写构造函数,编译器也会自动帮我们定义默认构造函数和拷贝构造函数(实践发现好像不会自定义参数构造函数

构造函数的名称与类的名称完全相同的,并且不会返回任何类型,也不会返回 void。

声明构造函数的时候是这样的:

1
2
3
4
5
6
7
8
class Line
{
double length;
public:
void setLength( double len );
double getLength( void );
Line(); // 这是构造函数
};

有三种构造函数:默认的、带参数的构造函数、拷贝构造函数

默认构造函数

默认构造函数在每次声明一个新的对象、并且没有初始化的时候都会被调用。

1
2
3
4
Line::Line(void)
{
cout << "Object is being created" << endl;
}

在后面的代码中,如果有

1
Line a,b;

“Object is being created” 就会被输出两遍。

参数构造函数

有两种写法,一种是普通的变量赋值,一种是使用初始化列表来初始化字段。

1
2
3
4
5
Line::Line( double len)
{
length = len;
cout << "Object is being created, length = " << len << endl;
}
1
2
3
4
Line::Line( double len): length(len)
{
cout << "Object is being created, length = " << len << endl;
}

两者是等价的。用初始化列表如果有多个变量要初始化,可以通过逗号划分。

1
2
3
4
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
....
}

拷贝构造函数

拷贝构造函数通过已经存在的相同类型的对象给新的对象赋值,主要用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象

  • 复制对象把它作为参数传递给函数

  • 复制对象,并从函数返回这个对象

一般形式如下:

1
2
3
Line (const Line &obj) {
// 构造函数的主体
}

classname a = b; 是会被调用,其中 b 是一个已经存在的对象。

如果有一个函数的参数是一个类,如 int getlength(Line line),那么在传参的时候,拷贝函数也会被调用。

如果一个函数的返回类型是一个类,如 Line addlen(Line a, Line b),那么在函数返回的时候,拷贝函数也会被调用。

析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

1
2
3
4
5
~Line(void)
{
cout << "释放内存" << endl;
delete ptr;
}

举个🌰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>

using namespace std;

class Line
{
public:
int getLength( void );
void setLength( int );
Line( void ); // 默认构造函数
Line( int len ); // 参数构造函数
Line( const Line &obj); // 拷贝构造函数
~Line(); // 析构函数

private:
int *ptr;
};

Line::Line(void) {
cout << "default constructor\n";
ptr = new int;
}

Line::Line(int len) {
cout << "parameter constructor\n";
ptr = new int;
*ptr = len;
}

Line::Line(const Line &obj) {
cout << "copy constructor\n";
ptr = new int;
*ptr = *obj.ptr;
}

Line::~Line(void) {
cout << *ptr << " ";
cout << "destructor\n";
delete ptr;
}

int Line::getLength(void) {
return *ptr;
}
void Line::setLength(int l) {
*ptr = l;
}

void display(Line obj) {
cout << "line = " << obj.getLength() <<endl;
}

Line add(Line a, Line b) {
Line line(a.getLength()+b.getLength());
return line;
}

int main( )
{
Line a(1), b;
b.setLength(2);

Line c = add(a,b);
display(c);

return 0;
}

The program’s output is …

1
2
3
4
5
6
7
8
9
10
11
12
13
parameter constructor     // 对象a的声明
default constructor // 对象b的声明
copy constructor // 对象a传参进入函数add
copy constructor // 对象b传参进入函数add
parameter constructor // add函数内部对象line的声明
1 destructor // add函数中对象a析构
2 destructor // add函数中对象b析构
copy constructor // 对象c传参进入函数display
line = 3
3 destructor // add函数返回的临时对象被析构
3 destructor // c被析构
2 destructor // b被析构
1 destructor // a被析构

你做对了吗?

友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend

(摘自菜鸟)

定义函数的时候不需要 :: 因为友元函数并不是类的成员。

内联函数

C++ 内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。

在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。

(摘自菜鸟)

当内联函数是一个比较小的函数,内联能够提高代码性能,否则得不偿失。

内联函数里一般不能用for,switch语句。

this 指针

在 C++ 中,this 指针是一个特殊的指针,它指向当前对象的实例。

在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。

this是一个隐藏的指针,可以在类的成员函数中使用,它可以用来指向调用对象。

当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为 this 指针。

友元函数没有 this 指针,因为友元不是类的成员,只有成员函数才有 this 指针。

摘自菜鸟

参考资料 Reference

https://www.runoob.com/cplusplus/cpp-classes-objects.html

https://blog.csdn.net/luoweifu/article/details/46959173

https://www.cnblogs.com/kunhu/p/3631285.html

https://www.cnblogs.com/wkfvawl/p/10620639.html