虚析构函数

若子类继承基类,两者析构函数不加virtual关键字,此时调用函数 参数为基类指针指向子类对象 删除对象,那么只会执行基类构造函数,此时对于编译器而言,你传进去的基类指针,在函数体已经静态编译好为基类的构造函数。

如果在基类的析构函数前加上virtual关键字,此时对于子类的析构函数,也会自动加上virtual关键字,从而加入到虚函数表中,再调用上面的函数,会首先寻找调用子类的析构函数,此时在子类的析构函数最后面,编译器会自动执行基类的析构函数

隐藏

当子类继承基类时,若函数名相同,参数名不同,此时基类有没有virtual关键字,函数都将被隐藏
当子类继承基类时,若函数名相同,参数相同,基类没有virtual关键字,此时基类函数将被隐藏

多态总结

1.基类(父类)里面的方法是用virtual关键字修饰,变成虚函数

2.子类继承父类重写父类里面的方法

3.用父类的指针或引用指向子类对象

4.通过父类指针或引用调用子类重写的父类方法

静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数就调用,没有的话就会发出警告或者报错;

静态多态:函数重载,泛型编程

动态多态是在程序运行时 根据基类的引用指向的对象来确定自己具体该调用哪一个类的虚函数。

动态多态:虚函数

作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。多态是设计模式的基础,多态是框架的基础。

继承和组合

继承格式

class 派生类名:继承方式 基类名1,继承方式 基类名2,.... { 派生类类体 };
继承方式有:public , protected,private

基类构造函数的调用,必须在派生类的初始化列表中指定传递参数。如果没有指定,则默认调用基类无参数的构造函数。

派生类对象仍无法直接访问基类的private成员变量

构造函数调用顺序:
先按照继承时的顺序挨个调用基类的构造函数,然后调用派生类的构造函数。

析构函数调用顺序和构造函数调用顺序相反

const用法

const 修饰的成员变量只能在构造函数的参数列表中初始化。
const 修饰的成员函数不能改变成员变量的值。
定义:
void function(void) const
const 修饰的对象只能调用常成员函数,不能调用非 常成员函数

static用法

static修饰局部变量时,用来延长生命周期。
修饰全局变量或者函数时,用来限制作用域
修饰静态成员变量的时候,所有的类对象共享此资源。
访问此资源时,既可以用类访问,也可以用对象访问。
记得要在类外初始化
static修饰静态成员函数的时候,静态成员函数没有this指针,也就不能访问非静态资源。
Q:什么时候使用静态成员函数?
当不需要实例化,不需要访问非静态资源,就有的确定行为
static语句放在public和private中是等效的

c++函数增强部分

c++的函数在声明的时候可以定义默认值参数,有几个注意事项:
1.当函数的定义和声明分开时,默认值参数只能在声明处定义
2.如果某个参数时默认参数,那么它后面的参数都必须是默认参数。


在同一目录下同时建立a.c和b.c,而且同时声明了相同函数名的函数,如果用c语言在main.c中想调用这两个文件中的相同函数,是很难办到的,即使你在某个文件中使用了static关键字表示作用域范围,也是很不方便的。在C++中的命名空间就很好的解决了这点。

tcp粘包解决方案

tcp是可靠的,面向字节流的协议,传输过程中可能就会

完整的服务器端代码:

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

#define BACKLOG 10

//./a.out ip port
int main(int argc,char *argv[])
{
int sfd,cfd,ret;
struct sockaddr_in svr_addr,cli_addr;
char buffer[1024] = {0};
ssize_t sbytes = 0,rbytes = 0;
int length;
int total_received;
socklen_t len = sizeof(struct sockaddr_in);
if (argc != 3){
fprintf(stderr,"Usage : %s < ip > < port >.\n",argv[0]) ;
exit(EXIT_FAILURE);
}

//1.创建套接字
sfd = socket(AF_INET,SOCK_STREAM,0);
if (sfd == -1){
perror("[ERROR] Failed to socket.");
exit(EXIT_FAILURE);
}

bzero(&svr_addr,sizeof(struct sockaddr_in));
svr_addr.sin_family = AF_INET;
svr_addr.sin_port = htons(atoi(argv[2]));
svr_addr.sin_addr.s_addr = inet_addr(argv[1]);

//2.绑定ip地址与端口号
ret = bind(sfd,(const struct sockaddr *)&svr_addr,sizeof(struct sockaddr));
if (ret == -1){
perror("[ERROR] Failed to bind.");
exit(EXIT_FAILURE);
}
//3.设置监听套接字为监听状态,建立监听队列
ret = listen(sfd,BACKLOG);
if (ret == -1){
perror("[ERROR] Failed to listen.");
exit(EXIT_FAILURE);
}

//4.与客户端进行三次握手,并建立连接,默认是阻塞
cfd = accept(sfd,(struct sockaddr *)&cli_addr,&len);
if (ret == -1){
perror("[ERROR] Failed to accpet.");
exit(EXIT_FAILURE);
}

printf("ip : %s port :%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
for(;;){
length = 0;
total_received = 0;
//接收数据的长度
rbytes = recv(cfd,&length,4,0);
if (rbytes == -1){
perror("[ERROR] Failed to recv.");
exit(EXIT_FAILURE);
}
for(;;){

rbytes = recv(cfd,buffer + total_received,length - total_received,0);
if (rbytes == -1){
perror("[ERROR] Failed to recv.");
exit(EXIT_FAILURE);
}else if (rbytes == 0){
printf("The client has been shutdown.\n");
}else if (rbytes > 0){
total_received += rbytes;
if (total_received == length)
break;
}
}
printf("buffer : %s\n",buffer);
sleep(1);
}

close(sfd);

return 0;
}

中特别要注意rbytes = recv(cfd,buffer + total_received,length - total_received,0);
这段代码的意思就是,从cfd中读取数据到buffer+已经接收的数据地址段,为什么要length+total_received,因为一段数据可能会被拆分发送,也就是说,如果只填length的话,第一次的recv可能只会接收前半段的拆分数据,那么后面的数据就接受不到。如果像上面正确设置,即使第一次没有接受完,因为total_received的值和length不等,就会在下个循环继续接收,接受的字节数就等于length-已经接受的字节数。

牢骚

真的不喜欢数据结构啊啊 链表什么的真讨厌啊啊啊啊 made真的恶心,各种结构体,遍历真的无趣T_T

还是先学着后面的吧,udp的局域网聊天先放一放,本来想着能实现也是很不错的,但是代码也不完整,等以后回头了,把这块和学生管理系统那块再统一看看T_T