主要内容
从C到C++
类和对象
操作符重载
继承与多态
异常和IO流
一,更好的C
1,语言风格更加简洁
2,类型检查更严格
void func(unsigned char* puc0{...}
int main(void){
func("hello");//报错 hello是const char*。指向的是字符串常量
//而函数参数不是const类型
return 0;
}
3,支持真正意义上的枚举类型
enum seaon{SPR,SUM,AUT,WIN};
SPR,SUM,AUT,WIN代表整数
season s = 0;
但是在C++中是错误的
C++中的枚举是真正的数据类型
4,参数匹配更精确
void func(int n){...}
void func(char c){...}
int main(void){
func('c');//根据参数的准确性进行匹配
}
5,禁止使用隐式声明
int main(void){
int n = func();
}
int func(void){
return 10;
}
在C中,如果返回值类型是int的,那么可以不声明
如果在C++中,则报错
在C++中没有隐式声明的那回事儿与上面的1,4是有联系的
二,第一个C++程序
hello.cpp
#include <iostream>
int main(void){
std::cout << "Hello C++ !" << std::endl;
std::cout << 123 << std::endl;
std::cout << 'A' << std::endl;
return 0;
}
注:"<<"是插入运算符
gcc编译C程序,g++编译C++程序
三,命名空间
1,名字空间指令
using namespace 名字空间名
2,名字空间声明
using 名字空间名::标识符
3,无名名字空间(匿名名字空间成员)
namespace{
名字空间成员;
}
引用方式:
::名字空间成员;
名字空间成员;
noname.cpp
#include <iostream>
using namespace std;
namespace{
void foo(void){
cout << "foo()" << endl;
}
}
void bar(void){//放在C++的无名名字空间中
cout << "bar()" << endl;
}
namespace ns1{
void foo(void){
cout << "ns1的foo()" << endl;
}
}
int main(void){
::foo();//两种调用方式
foo();
bar();
::bar();
return 0;
}
全部是调用了无名名字空间里面的foo()函数
注:在C++中,任何东西都是在名字空间中的,没有定义的就放在无名的里面
int main(void){
using ns1::foo;
::foo();
foo();
return 0;
}
无名的foo()
ns1中的foo();
在此处无名名字空间的foo()必须加::
四,C++的结构,联合和枚举(自定义数据类型)
1,C++的结构里面可以定义函数
2,C++里定义结构型变量的时候可以省略struct关键字
struct.cpp
#include<iostream>
using namespace std;
struct Student{
char name[128];
int age;
void print(void){
cout << name <<", " << age << endl;
}
}
int main(){
struct Student s = {"张飞",28};
Student ss = {"赵云",33};
printf("%s,%d\n",s.name,s.age);
s.print();
return 0;
}
3,C++中的声明联合类型的变量可以不加union关键字
int main(){
union{
int x;
char c[4];
};
x = 0x12345678;//c与x是重叠的
printf("%02X,%02X,%02X,%02X\n",c[0],c[1],c[2],c[3]);
return 0;
}
上面的程序还可以判断内存是小端还是大端地址
4,C++的枚举是一个独立的数据类型,而不是整数类型
五,C++的bool类型
C99中有了bool类型,但实际上是一个宏
bool类型变量只可以取true或者false
bool b = true;
bool b2 = false;
cout << b << ","<< b2 << endl;
结果:1,0
cout << boolalpha << b << "," << b2 << endl;
结果:true,false
cout << sizeof(bool) << endl;
结果是1
b=3.14;
cout << b << endl;
结果是:true
编译器认为非0都是true。
六,C++的运算符转换
&& and
|| or
& bitand
| bitor
七,C++的函数
1,重载:在同一作用域中,函数名相同,参数表不同的
函数之间构成重载关系
函数原型:函数类型+函数名+函数形参表
函数签名:函数名+函数形参表
C语言中,同一作用域中,函数名必须是唯一的
C++语言中,同一作用域中,函数签名必须是唯一的
完全匹配>常量转换>升级转换>标准转换>自定义转换>省略号匹配
常量转换:形参是常量,实参是变量,这样转换安全
标准转换:损失精度
int foo(char c){...}
int (*pfunc)(char) = foo;//函数指针
pfunc('A');
当使用函数指针的时候,有多个函数,但是要调用哪个函数呢?
函数指针的类型决定其具体指向的重载版本,而不是由实参的类型决定
为什么C语言中不可以函数重名,而C++可以呢?
因为在编译的时候进行了函数名置换
通过extern "C"可以指示编译器以C语言的方式处理函数(不做函数名置换)
防止一个C文件一个C++文件编译过后二者之间的调用出现问题
2,缺省参数
testcpp.cpp
void bar(int n,double f = 1.2,char c = 'A'){
cout <<n << "," << f << "," << c << endl;
}
当不给实参的时候取缺省值
注:1)缺省参数都必须靠右
2)如果为一个参数指定了缺省值,这个参数右边所有参数都必须指定缺省值
3)缺省参数和重载要避免歧义
4)缺省参数只能用在函数的声明中
3,哑元
1)函数中带有一个参数,但是不使用
2)借助哑元参数保证函数的向后兼容
3)借助哑元实现函数的重载。
4,内联 inline
#include<iostream>
using namespace std;
#define SQUARE(x) (x*x)
int main(void){
cout << SQUARE(10) << endl;
cout << SQUARE(3+7) << endl; //3+7*3+7
//#define SQUARE(x) ((x)*(x))这样可以实现想要的结果
return 0;
}
结果:100
31
宏扩展不是函数调用,不会算表达式。仅仅是字符集的替换
函数调用是有成本的,函数调用就有参数检查,保护现场,压栈等等
int square(int x){
return x * x;
}
inline int square(int x){
return x * x;
}
宏是在预编译的时候进行的,进行代码级的替换
内联是将二进制代码嵌入到指定的位置
总之:
1)内联函数保持了函数的特性,同时避免了函数调用的开销
2)inline关键字仅仅表示希望该函数被编译为内联,究竟会不会成内联,
由编译器决定。通常情况下,大函数和递归函数不会被处理为内联
内联是用牺牲空间换取时间
八,内存分配
new /delete ------ new和delete是操作符
new.cpp
#include<iostream>
using namespace std;
int main(){
//C
int* p1 = (int*) malloc(sizeof(int));
*p1 = 123;
cout << *p1 << endl;
free(p1);
//C++
p1 = new int(123);
cout << *p1 << endl;
delete p1;
p1 = new int[5];
for(int i = 0; i < 5; i++){
p1[i] = i * 10;
}
delete[] p1;//delete p1;仅仅释放第一个元素,后面四个没释放
return 0;
}
如果内存是以数组的形式分配的,那么也应该按照数组的方式释放
delete[]
new可能会失败,这时会抛出bad_alloc异常,程序应该捕获并处理该异常
,否则进程将被系统杀死。
九,引用
引用实际上是一个变量的别名。
ref.cpp
#include<iostream>
using namespace std;
int main(void){
int n = 100;
int& r = n;
r = 20;//将20赋给了r所引用的变量
cout << n << endl;
int* p = &n;
*p = 20;
cout << n << endl;
return 0;
}
指针可以不初始化(野指针),但是引用必须在声明的同时初始化
引用已被初始化,再不能引用其他变量
引用不能引用常量,只有const型引用才能引用常量
例如:int& rc = 10;//错误
const int& rc = 10;//正确
不能对常引用做赋值
rc = 20;//错误
从C到C++
类和对象
操作符重载
继承与多态
异常和IO流
一,更好的C
1,语言风格更加简洁
2,类型检查更严格
void func(unsigned char* puc0{...}
int main(void){
func("hello");//报错 hello是const char*。指向的是字符串常量
//而函数参数不是const类型
return 0;
}
3,支持真正意义上的枚举类型
enum seaon{SPR,SUM,AUT,WIN};
SPR,SUM,AUT,WIN代表整数
season s = 0;
但是在C++中是错误的
C++中的枚举是真正的数据类型
4,参数匹配更精确
void func(int n){...}
void func(char c){...}
int main(void){
func('c');//根据参数的准确性进行匹配
}
5,禁止使用隐式声明
int main(void){
int n = func();
}
int func(void){
return 10;
}
在C中,如果返回值类型是int的,那么可以不声明
如果在C++中,则报错
在C++中没有隐式声明的那回事儿与上面的1,4是有联系的
二,第一个C++程序
hello.cpp
#include <iostream>
int main(void){
std::cout << "Hello C++ !" << std::endl;
std::cout << 123 << std::endl;
std::cout << 'A' << std::endl;
return 0;
}
注:"<<"是插入运算符
gcc编译C程序,g++编译C++程序
三,命名空间
1,名字空间指令
using namespace 名字空间名
2,名字空间声明
using 名字空间名::标识符
3,无名名字空间(匿名名字空间成员)
namespace{
名字空间成员;
}
引用方式:
::名字空间成员;
名字空间成员;
noname.cpp
#include <iostream>
using namespace std;
namespace{
void foo(void){
cout << "foo()" << endl;
}
}
void bar(void){//放在C++的无名名字空间中
cout << "bar()" << endl;
}
namespace ns1{
void foo(void){
cout << "ns1的foo()" << endl;
}
}
int main(void){
::foo();//两种调用方式
foo();
bar();
::bar();
return 0;
}
全部是调用了无名名字空间里面的foo()函数
注:在C++中,任何东西都是在名字空间中的,没有定义的就放在无名的里面
int main(void){
using ns1::foo;
::foo();
foo();
return 0;
}
无名的foo()
ns1中的foo();
在此处无名名字空间的foo()必须加::
四,C++的结构,联合和枚举(自定义数据类型)
1,C++的结构里面可以定义函数
2,C++里定义结构型变量的时候可以省略struct关键字
struct.cpp
#include<iostream>
using namespace std;
struct Student{
char name[128];
int age;
void print(void){
cout << name <<", " << age << endl;
}
}
int main(){
struct Student s = {"张飞",28};
Student ss = {"赵云",33};
printf("%s,%d\n",s.name,s.age);
s.print();
return 0;
}
3,C++中的声明联合类型的变量可以不加union关键字
int main(){
union{
int x;
char c[4];
};
x = 0x12345678;//c与x是重叠的
printf("%02X,%02X,%02X,%02X\n",c[0],c[1],c[2],c[3]);
return 0;
}
上面的程序还可以判断内存是小端还是大端地址
4,C++的枚举是一个独立的数据类型,而不是整数类型
五,C++的bool类型
C99中有了bool类型,但实际上是一个宏
bool类型变量只可以取true或者false
bool b = true;
bool b2 = false;
cout << b << ","<< b2 << endl;
结果:1,0
cout << boolalpha << b << "," << b2 << endl;
结果:true,false
cout << sizeof(bool) << endl;
结果是1
b=3.14;
cout << b << endl;
结果是:true
编译器认为非0都是true。
六,C++的运算符转换
&& and
|| or
& bitand
| bitor
七,C++的函数
1,重载:在同一作用域中,函数名相同,参数表不同的
函数之间构成重载关系
函数原型:函数类型+函数名+函数形参表
函数签名:函数名+函数形参表
C语言中,同一作用域中,函数名必须是唯一的
C++语言中,同一作用域中,函数签名必须是唯一的
完全匹配>常量转换>升级转换>标准转换>自定义转换>省略号匹配
常量转换:形参是常量,实参是变量,这样转换安全
标准转换:损失精度
int foo(char c){...}
int (*pfunc)(char) = foo;//函数指针
pfunc('A');
当使用函数指针的时候,有多个函数,但是要调用哪个函数呢?
函数指针的类型决定其具体指向的重载版本,而不是由实参的类型决定
为什么C语言中不可以函数重名,而C++可以呢?
因为在编译的时候进行了函数名置换
通过extern "C"可以指示编译器以C语言的方式处理函数(不做函数名置换)
防止一个C文件一个C++文件编译过后二者之间的调用出现问题
2,缺省参数
testcpp.cpp
void bar(int n,double f = 1.2,char c = 'A'){
cout <<n << "," << f << "," << c << endl;
}
当不给实参的时候取缺省值
注:1)缺省参数都必须靠右
2)如果为一个参数指定了缺省值,这个参数右边所有参数都必须指定缺省值
3)缺省参数和重载要避免歧义
4)缺省参数只能用在函数的声明中
3,哑元
1)函数中带有一个参数,但是不使用
2)借助哑元参数保证函数的向后兼容
3)借助哑元实现函数的重载。
4,内联 inline
#include<iostream>
using namespace std;
#define SQUARE(x) (x*x)
int main(void){
cout << SQUARE(10) << endl;
cout << SQUARE(3+7) << endl; //3+7*3+7
//#define SQUARE(x) ((x)*(x))这样可以实现想要的结果
return 0;
}
结果:100
31
宏扩展不是函数调用,不会算表达式。仅仅是字符集的替换
函数调用是有成本的,函数调用就有参数检查,保护现场,压栈等等
int square(int x){
return x * x;
}
inline int square(int x){
return x * x;
}
宏是在预编译的时候进行的,进行代码级的替换
内联是将二进制代码嵌入到指定的位置
总之:
1)内联函数保持了函数的特性,同时避免了函数调用的开销
2)inline关键字仅仅表示希望该函数被编译为内联,究竟会不会成内联,
由编译器决定。通常情况下,大函数和递归函数不会被处理为内联
内联是用牺牲空间换取时间
八,内存分配
new /delete ------ new和delete是操作符
new.cpp
#include<iostream>
using namespace std;
int main(){
//C
int* p1 = (int*) malloc(sizeof(int));
*p1 = 123;
cout << *p1 << endl;
free(p1);
//C++
p1 = new int(123);
cout << *p1 << endl;
delete p1;
p1 = new int[5];
for(int i = 0; i < 5; i++){
p1[i] = i * 10;
}
delete[] p1;//delete p1;仅仅释放第一个元素,后面四个没释放
return 0;
}
如果内存是以数组的形式分配的,那么也应该按照数组的方式释放
delete[]
new可能会失败,这时会抛出bad_alloc异常,程序应该捕获并处理该异常
,否则进程将被系统杀死。
九,引用
引用实际上是一个变量的别名。
ref.cpp
#include<iostream>
using namespace std;
int main(void){
int n = 100;
int& r = n;
r = 20;//将20赋给了r所引用的变量
cout << n << endl;
int* p = &n;
*p = 20;
cout << n << endl;
return 0;
}
指针可以不初始化(野指针),但是引用必须在声明的同时初始化
引用已被初始化,再不能引用其他变量
引用不能引用常量,只有const型引用才能引用常量
例如:int& rc = 10;//错误
const int& rc = 10;//正确
不能对常引用做赋值
rc = 20;//错误