这个排版太难了,就没牌了。在百度网盘c++笔记中自己找
一、 C++ 2
1、 C++的头文件 2
2、 命名空间 2
3、 更严格的类型转化 2
4、 new和delete 2
5、 内联函数 2
6、 引用 2
7、 函数的重载 3
8、 函数模板(后面还会讲class模板) 3
二、 类和对象 4
1、 C++类成员的保护 4
2、 C++类的本质 4
3、 类的作用域 4
4、 类的构造和析构函数 4
5、 构造函数的初始化成员列表 5
6、 拷贝构造函数 5
7、 常量类成员,常量对象。 5
8、 explicit 6
9、 this指针 6
10、 类的static成员变量 6
三、 C++封装与移植训练 7
1、 UDP协议 7
2、 C和C++混合编程(在C++中调用自己的c函数) 8
3、 makefile 9
四、 拷贝构造复习 11
1、 拷贝构造函数: 11
2、 以下情况都会调用拷贝构造函数: 11
3、 传参: 11
五、 友元机制 12
1、 友元定义: 12
2、 友元函数 12
3、 友元类 12
4、 注意: 12
5、 12
六、 操作符重载 13
1、 重载定义: 13
2、 不能重载的操作符: 13
3、 重载规则 13
4、 成员函数的语法形式为: 13
5、 几种情况(具体看overload.cpp) 13
6、 二元与一元重载 13
一、C++
1、C++的头文件
①.传统的C头文件,
Eg : <stdio.h>
②.C++头文件
Eg : <iostream>
③.hpp文件件
Eg : <happy.hpp>
2、命名空间
①.C++引入了新的概念,命名空间可以有效避免大型项目中的各种名称冲突
②.class关键字
③.class是C++的核心,是面向对象编程的核心内容
3、更严格的类型转化
①.在C++,不同类型的指针是不能直接赋值的,必须强转
Eg : void *p ;
int *a = (void *)p ;(这是C语言风格的类型强制转换)
4、new和delete
①.new和delete是C++内建的操作符,不需要有任何头文件,用new分配的内存必须用delete释放,不要用free。
②.new创建数组的方法new[];
5、内联函数
①.inline关键字的意思是,内联函数不作为函数调用,而是直接把内联函数的代码嵌入到调用的语句中
②.内联函数适合函数代码很少,并且频繁的大量调用。
6、引用
①.引用就是一个变量的别名,而不是地址
②.引用必须在定义的时候就被赋值,(在真实的变量没出来之前怎么会有别名呢)
Eg :
int a = 2 ;
Int &b = a ; (这样可以)
/******************/
Int &b ;
Int a = 2 ;
b = a ;(这样不行)
③.函数的缺省参数(必须放在后面)
Eg :
void myFunction(int a , int b , int c=2 ) ;(可以)
Void myFunction(int a=2 , int b , int c ) ; (不可以)
④.C++允许函数在定义的时候,提供缺省参数,如果调用函数的时候没有提供形参,那么形参的值就是缺省值
⑤.引用做为函数的参数,没有出栈,入栈操作,所以效率更高
⑥.如果要使引用参数的值不能在函数内部被修改,那么就定义为常量引用 const &
7、函数的重载
①.函数的名称是一样的,但参数不同可以重载
②.函数参数相同,
③.注意:
当函数的缺省参数缺省后系统不知道调用哪个函数时,是不允许的。
8、函数模板(后面还会讲class模板)
①.模板的形式:
Template < typename T>
通用函数定义
或是:
Template < class T >
通用函数定义
Eg :
Template < class T >
T max( T a , T b ){
return a * b ;
}
二、类和对象
1、C++类成员的保护
①.如果类函数返回的是成员变量的指针,为了避免在类外部成员变量被修改,所以函数就要返回常量指针
Eg : const char * mychen() {
Return “hello” ;
}
Main(){
Char * p = (char *)mychen() ;
P = “work” ;(这通过强转是可以改的)
}
②.如果一个类成员变量和一个全局变量重名,那么在类成员函数当中默认访问的是类的成员变量.
③.在类的内部访问全局标识,关键字 ::
注意:这是在类的外部定义了全局函数或是全局变量,在类的内部采用这种::表示方式。
Eg :
int age = 2 ;
Class a {
Public :
Void getAge(){
::age = 55 ;(这就是在类的内部访问全局变量)
}
}
2、C++类的本质
①.类其实就是结构的数据成员加可执行代码,统一提供封装,继承,多态。
②.在类内部,没有权限限定符,默认是private
③.在结构内部,没有权限限定符,默认是public
3、类的作用域
①.类成成员变量作用域局限于类内部,类的外部是不可见。
4、类的构造和析构函数
①.构造函数名称和类的名称一致,而且没有返回值
②.一个类实例化为一个对象的时候,自动调用。
class Chen {
private :
public :
Chen() ;(构造函数)
~Chen() ;(析构函数,构造函数前面加了~)
}
③.一个对象在销毁的时候会自动调用析构函数。
④.默认有构造和析构函数,什么都不做。
5、构造函数的初始化成员列表
①.初始化成员列表只能在构造函数使用
②.const成员必须用初始化成员列表赋值
A.h
namespace wei {
class chen{
private :
int age ;
const int face ;
public :
chen() ;(构造函数)
}
} ;
A.cpp
namespace wei {
(构造函数初始化)
Chen ::chen() : age(50).face(55){
age = 60 ;(这两种初始化方式都是可以的)
face = 11 ;(不可以,必须通过初始化成员列表赋值)
}
} ;
③.引用数据成员必须用初始化成员列表赋值
④.原则:
由于析构函数只有一个,所以在不同的构造函数里面给函数的成员指针分配内存的时候,一定要统一new或者new[]
6、拷贝构造函数
①.浅拷贝
两个对象之间成员变量简单的赋值。
②.深拷贝
不同的对象指针成员指向不同的内存地址,拷贝构造的时候不是简单的指针赋值,而是将内存拷贝过来。
③.原则:
如果类成员有指针,那么需要自己实现拷贝构造函数,不然存在浅拷
7、常量类成员,常量对象。
①.类成员后面跟关键字const意思是告诉编译器,这个函数内部不会对类成员变量做任何修改。
Eg :
Void my() const { //(表明这个函数不会对修改类成员)
}
②.函数的参数如果是一个类,那么就用类的引用。如果不想参数被调用函数内部修改,那么就采用const &
8、explicit
①.告诉C++编译器,要明确的调用这个构造函数,而不要自作聪明的认为=操作符是要调用构造的。
Eg :
class chen{
private :
int age ;
public :
explicit chen(int age) ;
}
chen::chen( int age) {
This->age = age ;
}
main{
chen c = 2 ; (这样会默认调用构造函数chen(2) , 构造函 数前面加explicit这个关键字,则不可以这样写)
}
9、this指针
①.this就是指向自己实例的指针
10、类的static成员变量
①.static变量是放到静态内存区的,程序加载就存在,一直到程序退出才清理。
②.类的静态成员初始化,
Eg :
int chen::age = 55 ;(不可以在类构造函数和初始化成员列表中初
始化,必须在类外初始化)
③.类的static成员和类的对象没有直接关系,类的静态成员是放到静态内存区的,程序开始执行就存在,一直到程序结束才清理。
④.类的静态成员变量不论类的实例有多少,但成员变量只有一份。
⑤.
三、C++封装与移植训练
(在linux里写的程序直接到window下就能使用,反之需要修改)注意:这里写了一个程序,结合程序会更好理解封装和移植,程序放在同个路径下myudp工程里面。
1、UDP协议
①.TCP/IP
②.UDP协议是基于IP
③.socket把网络协议用C语言封装成一个个函数,放到dll,供其他语言调用,
④.阻塞,一个函数在没有返回之前,程序被挂起.
⑤.recvfrom就是一个阻塞的函数
⑥.网络是字节流,发送是以字节为单位的,如果大于一个字节的数据类型通过网络发送的时候必须调用htons或者htonl函数将数据转化为正确的网络字节流才能发送
windows底层的socket,Ws2_32.lib(socket库)
127.0.0.1,这个IP地址就代表自己。
0,代表自己
255广播
192.168.6.1 192.168.6.254
2、C和C++混合编程(在C++中调用自己的c函数)
①.对于C语言来讲,编译完成之后函数的名称不会改变,对于C++来讲函数的名称发生变化;(所以要用extern “C”)
②.如果是C代码中的函数,在C++中使用一定要用extern “C”关键字来说明;
③.对于操作系统来讲,一定要避免两个程序同时绑定到一个端口。
④.在c++中调用c文件中的函数,如果是提供源文件给其他人调用,则称为混合编程,不过这样别人就可以改变自己的源码。一般不这样用,都是将c文件动态库.so文件给其他人调用。则提供的头文件应该这样写,
Eg:
(假设这里有一个叫a.h的文件,文件里面有个函数max)
#ifndef A_H
#define A_H
extern “C”{
int max(int a , int b ) ; (这是申明)
}
#endif
——->>问题?
——->>既然是动态库,应该是c程序也能调用才对吧,但是c语言
——->>中没有extern “C”这种用法,所以引用这个头文件在c程
——->>序中会报错。
——->>改进。。。。
Eg:
(假设这里有一个叫a.h的文件,文件里面有个函数max)
(__cplusplus宏,如果是c++编译器的话,会自动生成)
#ifndef A_H
#define A_H
#ifdef __cpluscplus (两个下划线)
extern “C”{
#endif
int max(int a , int b ) ; (这是申明)
#ifdef __cpluscplus
}
#endif
#endif
3、makefile
①.gcc编译过程
②.gcc参数
③.-o 指定输出文件名
④.-c 只编译,不链接
⑤.-E预编译
⑥.make是根据.cpp和.o文件的最后修改日期判断cpp文件是否需要编译。如果.o文件不存在,make会失去判断条件,那么一定会编译cpp文件。
⑦.在unix下so文件一定要以lib开头,以so结尾
⑧.gcc参数-iPIC生成和位置无关的代码,
Eg :
CC=g++ (在makefile中变量用大写,定义变量CC)
SRCS=main.cpp\ (\表示换行,工程里的cpp文件多必须换行)
max.cpp
OBJC=$(SRCS:.cpp=.o) (根据cpp文件,写相应的.o文件,:.)
EXEC=main (定义变量EXEC)
target: $(OBJC) (开始编写规则:规则名target:依赖项)
$(CC) $(OBJC) -o $(EXEC)
.cpp.o : (表示,根据.cpp文件生成.o文件)
$(CC) -c $< -o $@ ( $@ 依赖项 $< 全部完整文件名)
clean :
rm -fr $(EXEC) $(OBJC)
四、拷贝构造复习
1、拷贝构造函数:
wei::wei(const wei &it){
this->age = it.age ;
cout<<”拷贝构造”<