1.面向过程(PO)和面向对象(OO)
对比项 | 面向过程 | 面向对象 |
定义 | 把问题分解成一个个步骤,每个步骤用函数实现,依次调用即可 | 把数据及对数据的操作方法 放在一起,作为一个相互依存的整体——对象;对同类对象抽象出其共性,形成类。 |
特点 | 算法+数据结构 | 封装、继承、多态 |
优势 | 性能比面向对象高 因为类调用时需要实例化,开销比较大,比较消耗资源; 比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。 | 易维护、易复用、易扩展 由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护 |
劣势 | 难以应对复杂系统,难以复用,不易维护、不易扩展 | 比较抽象、性能比面向过程低 |
设计语言 | C、Fortran | Java、Smalltalk、EIFFEL、C++、Objective-、C#、Python等 |
英文名 | (Procedure Oriented,PO) | (Object Oriented,OO) 面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP) |
思想 | 程序=算法+数据结构、自上而下 | 对象=算法+数据结构、自下而上 |
把大象塞进冰箱需要几步? | 1、打开冰箱 2、把大象塞进去 3、关上冰箱 | 大象: 1、走进冰箱 冰箱: 1、开门 2、关门 |
面向对象三大特性:
封装:把客观事物封装成抽象的类。并且类可以把自己的数据和方法只让可信的类或者对象 操作,对不可信的进行信息隐藏
继承:从已有的类(父类)派生出新的类(子类)
多态:一个类实例的相同方法在不同情形有不同表现形式
2. :: 作用域运算符
解决归属问题(谁是谁的谁)
3.命名空间(namespace)
在大规模的程序设计中,以及各种c++库 中,为防止标识符命名冲突,引入关键字namespace。
名称(name)可以是 符号常量、变量、函数、结构、枚举、类和对象等等。
3.1创建命名空间
- 命名空间只能全局范围内定义
正确示例:
错误示例:
- 命名空间可嵌套定义
- 命名空间是开放的,随时可加成员,且不用到最早的定义处加
- 声明 和 实现 可分离(可以在外部写函数的具体实现)
- 无名命名空间
命名空间中的标识符只能在 本文件 中访问,相当于加了个 static,使其可以作为 内部连接
- 命名空间别名
3.2 using声明
3.2.1 声明 命名空间中的成员 可用
namespace A
{
int paramA=20;
void funcA(){cout<<"hello"<<endl;}
}
void test()
{
using A::paramA;
cout<<paramA<<endl;
cout<<A::paramA<<endl;
//int paramA=10;//同名冲突
}
- 推荐使用 命名空间作用域运算符 去使用对象,不然可能有同名冲突
- using声明碰到函数重载
如果命名空间包含一组相同名字重载的函数,using声明则声明了这个重载函数的所有集合
namespace A
{
void func(){}
void func(int x){}
void func(int x,int y){}
}
void test()
{
using A::func;
func();
func(10);
func(10,20);
}
3.2.2 声明 整个命名空间 可用
using namspace A;
*注意:对变量的查找顺序是 局部->全局->命名空间
4.struct类型增强
4.1 定义结构体变量不需要加 struct 关键字
c中定义结构体:struct Stu luck;
c++中定义结构体:Stu luck;(加struct也对)
4.2 c++结构体既可定义 成员变量 ,也可定义 成员函数
struct Stu
{
string mname;
int mnum;
void setname(string name){mname=name;
}
5.加了 bool类型关键字
- bool类型有两个值:true(转成1),false(转成0)
- 非零值转成true(1),零值转成false(0)
- 这三个都是关键字
- bool类型占一个字节
6.引用(reference)
c++与c指针作用基本一样,但c++增加了另外一种函数传递地址的途径,即引用传递(pass-by-reference)
变量 的实质:一段连续内存空间的别名。
引用 的本质:给一个 已经定义了的变量 取别名。
void test()
{
int a=10;int &b=a; //普通变量的引用
int arr[5]={1,2,3,4,5};
int (&myarr)[5]=arr; //数组的引用
int num=10;
int *p=#
int* &myp=p; //指针变量的引用
void func(void)
{cout<<"hello"<<endl;}
void (&myfunc)(void)=func; //函数的引用
}
- 引用必须初始化
- 系统不会为引用开辟空间
6.1引用作为函数参数
函数内部可以通过 引用 操作外部变量 (c++用 指引 代替 指针 传参更好,指针是c的精髓,c++造出引用代替指针)
6.2引用作为函数返回值
1.不要返回普通局部变量的引用
int& test(void)
{
int num=10;
return num;//不要这样,num是局部变量
}
int main()
{
int &b=test(); //b就是num的别名,但是num被释放了,相当于给一个被释放的空间取别名,会出现段错误
}
2.返回值类型为引用,可以完成链式操作。
6.3常引用
6.3.1给常量取别名,不能通过常引用修改内容
6.3.1常引用作为函数参数,既节约空间,又防止函数内部修改外部变量的值
7.内联函数
7.1声明内联函数
在编译阶段,将内联函数的函数体,替换函数调用处,避免函数调用时的开销
定义时用 inline 关键字修饰,声明时不需要
int myAdd(int x,int y);
inline int myAdd(int x,int y)
{return x+y;}
7.2宏函数 和 内联函数 的区别
对比项 | 宏函数 | 内联函数 |
---|---|---|
展开阶段 | 预处理 | 编译 |
参数类型 | 无,不能保证参数完整性 | 有,能保证参数完整性 |
作用域限制 | 无,不能作为命名空间、结构体、类的成员 | 有,能作为命名空间、结构体、类的成员 |
7.3 内联函数条件
不满足条件,加了 inline 也不一定是内联函数 ;
有时候不加 inline 也是内联函数;
内不内联由编译器决定。
- 不能存在任何形式的循环语句
- 不能存在过多的条件判断语句
- 函数体不能过于庞大
- 不能对函数取的值
类中的成员默认都是内联函数,不加 inline 也是内联函数
8.函数重载
含义:同一个函数名代表不同的函数功能
条件:同一作用域,函数的 参数类型、个数、顺序不同 都可以作为重载。返回值不能作为重载条件
(编写程序过程中可以忽略返回值,一个函数为 int func(int x),另一个函数为void func(int x),直接调用func(10),不知道要调用谁)
特性:函数重载是C++ 多态 的特性(静态多态)
底层实现原理:重载函数在 linux 编译下会生成新的函数名
9.函数的默认参数
c++在声明函数原型时可为一个或多个参数指定 默认(缺省)的参数值。当函数调用没有传参时,会默认使用这个值。
void test1(int a=10,int b=20)
{cout<<a+b<<endl;}//注意点:
//1.形参b设置默认参数值,那后面的形参也需要设置默认参数。
void test2(int a,int b=10,int c=10);//2.如果函数声明和函数定义分开,函数声明设置了默认参数,函数定义不能再设置默认参数。
void test3(int a=0,int b=0);
void test3(int a,int b){}
//3.默认参数 和 函数重载 同时出现时,注意二义性。
void test2(int a,int b=10);
test2(10,20);//可能是c使用了默认值,也可能是重载函数,无法确定
int main(){
//1.如果没有传参数,那么使用默认参数。
void test1();
//2.如果传一个参数,那么第2个参数使用默认参数。
void test1(100);
//3.如果传入2个参数,那么2个参数都使用传入参数。
void test1(100,200);
}
10.占位参数
有参数类型,无参数名。
1.函数内部无法使用占位参数。
2.占位参数也可以设置默认值,但依旧用不了。
3.传参时也要传占位参数的值。
11.extern "C"
c:void func(){} 被编译成 func
c++:void func(){} 被编译成 _Z6funcv
如果在C++中调用C的函数,会默认去找_Z6funcv。但是该函数对应的是func,导致找不到。
extern "C"
{
//在这里面声明从c引用的函数
extern void func();
}