C语言和C++语言关系
C语言是在实践的过程中逐步完善起来的
没有深思熟虑的设计过程,使用时存在很多“灰色地带” ,残留量过多低级语言的特征 ,直接利用指针进行内存操作。
当面向过程方法论暴露越来越多的缺陷的时候,业界开始考虑在工程项目中引入面向对象的设计方法,而第一个需要解决的问题就是:高效的面向对象语言,并且能够兼容已经存在的代码。
C语言 + 面向对象方法论——》Objective C /C++
C语言和C++并不是对立的竞争关系
C++是C语言的加强,是一种更好的C语言
C++是以C语言为基础的,并且完全兼容C语言的特性
学习C++并不会影响原有的C语言知识,相反会根据加深对C的认知;
学习C++可以接触到更多的软件设计方法,并带来更多的机会。
1) C++是一种更强大的C,通过学习C++能够掌握更多的软件设计方法
2) C++是Java/C#/D等现代开发语言的基础,学习C++后能够快速掌握这些语言
3)C++是各大知名软件企业挑选人才的标准之一
一 面向过程的程序设计方法
1 设计思路:自顶向下、逐步求精。采用模块分解与功能抽象,自顶向下、分而治之。
2 程序结构:
1)按功能划分为若干个基本模块,形成一个树状结构
2)各模块间的关系尽可能简单,功能上相对独立;
每一模块内部均是由顺序、选择和循环三种基本结构组成。
3) 其模块化实现的具体方法是使用子程序。
3 优点
有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。
4 缺点
1) 可重用性差、数据安全性差、难以开发大型软件和图形界面的应用软件;
2) 把数据和处理数据的过程分离为相互独立的实体
3) 当数据结构改变时,所有相关的处理过程都要进行相应的修改。4
4) 每一种相对于老问题的新方法都要带来额外的开销。
5) 图形用户界面的应用程序,很难用过程来描述和实现,开发和维护也都很困难。
二 面向对象的程序设计方法
1 将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体——对象。
2 对同类型对象抽象出其共性,形成类。
3 类通过一个简单的外部接口,与外界发生关系;
4 对象与对象之间通过消息进行通信。
三 面向对象的基本概念
1 对象:是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。
2 类:具有相同属性和服务的一组对象的集合
3 封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
4 多态:多态是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
C++对C的加强
1 namespace命名空间
所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
C中的命名空间
在C语言中只有一个全局作用域
C语言中所有的全局标识符共享同一个作用域
标识符之间可能发生冲突
C++中提出了命名空间的概念
命名空间将全局作用域分成不同的部分
不同命名空间中的标识符可以同名而不会发生冲突
命名空间可以相互嵌套
全局作用域也叫默认命名空间
一 :<\ostream>和<\iostream.h>
当使用<\iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;C语言中只有一个全局作用域.后缀为.h的头文件c++标准已经明确提出不支持了。
当使用<\iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。
二: 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:
1、直接指定标识符。例如std::ostream而不是ostream。完整语句如下: std::cout << std::hex << 3.4 << std::endl;
2、使用using关键字。 using std::cout; using std::endl; using std::cin; 以上程序可以写成 cout << std::hex << 3.4 << endl;
3、最方便的就是使用using namespace std;
C++命名空间的定义:
namespace name { … }
C++命名空间的使用:
使用整个命名空间:using namespace name;
使用命名空间中的变量:using name::variable;
使用默认命名空间中的变量:::variable
默认情况下可以直接使用默 认命名空间中的所有标识符
namespace NameSpaceA //定义命名空间
{
int a = 0;
}
namespace NameSpaceB
{
int a = 1;
namespace NameSpaceC // 命名空间嵌套定义
{
struct Teacher
{
char name[10];
int age;
};
}
}
int main01()
{
using namespace NameSpaceA; //使用命名空间
using NameSpaceB::NameSpaceC::Teacher;//使用嵌套命名空间中的变量
printf("a = %d\n", a);
printf("a = %d\n", NameSpaceB::a);//
NameSpaceB::NameSpaceC::Teacher t2
Teacher t1 = {"aaa", 3};
printf("t1.name = %s\n", t1.name);
printf("t1.age = %d\n", t1.age);
system("pause");
return 0;
}
void main()
{
using namespace namespaceA;
using namespace namespaceB;
cout<<namespaceA::a<<endl;//输出命名空间中的值
cout<<namespaceB::a<<endl;//输出命名空间中的值
using namespaceB::namespaceC::Teacher ;
Teacher t2;
t2.age = 36;
system("pause");
}
2 register关键字增强
register关键字 请求编译器让变量a直接放在寄存器里面,速度快。
区别:
1 C语言中无法取得register变量地址
2 在C++中依然支持register关键字:
C++编译器有自己的优化方式,即使不使用register也可能做优化
C++中可以取得register变量的地址
C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。
void main()
{
register int a = 0;
printf("&a: %d \n", &a); //在C语言中这行报错。
for (int i=0; i<1000; i++) //不使用register也可能做优化
{
printf("i:%d \n", i);
}
system("pause");
}
3变量检测增强
在C语言中,重复定义多个同名的全局变量是合法
在C++中,不允许定义多个同名的全局变量,C++直接拒绝这种二义性的做法。
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
int g_var;
int g_var = 1;
4 struct类型加强
struct类型的加强:
C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
C++中的struct是一个新类型的定义声明
struct Student
{
char name[100];
int age;
};
int main(int argc, char *argv[])
{
Student s1 = {"wang", 1};//C语言执行报错,需要加上struct关键字
Student s2 = {"wang2", 2};
return 0;
}
5 新增Bool类型关键字
C++在C语言的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
理论上bool只占用一个字节,
如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现
true代表真值,编译器内部用1来表示
false代表非真值,编译器内部用0来表示
bool类型只有true(非0)和false(0)两个值
C++编译器会在赋值时将非0值转换为true,0值转换为false
6 三目运算符功能增强
1 C语言中的三目运算符返回的是变量值,不能作为左值使用;
2 C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方;
注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用(a < b ? 1 : b )= 30
3 本质
c++编译器 帮我们程序员完成了 取地址的工作
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 20;
int var = 100;
var = 101;
//返回一个最小数 并且给最小数赋值成3
//三目运算符是一个表达式 ,表达式不可能做左值
(a < b ? a : b )= 30;
int z = (a < b ? a : b );
printf("a = %d, b = %d\n", a, b);//a =30,b =10
system("pause");
return 0;
}
7 新增引用
1 概念
引用可以看作一个已定义变量的别名,引用的语法:Type& name = var;、
int main()
{
int a = 10; //c编译器分配4个字节内存。。。a内存空间的别名
int &b = a; //b就是a的别名。。。
a = 11; //直接赋值
b = 14;
printf("a:%d b:%d", a, b);
system("pause");
return 0;
}
2 引用做函数参数
普通引用在声明时必须用其它的变量进行初始化,引用作为函数参数声明时不进行初始化
//复杂数据类型 的引用
struct Teacher
{
char name[64];
int age ;
};
void printfT(Teacher *pT)
{
cout<<pT->age<<endl;
}
//pT是t1的别名 ,相当于修改了t1
void printfT2(Teacher &pT)
{
//cout<<pT.age<<endl;
pT.age = 33;
}
//pT和t1的是两个不同的变量
void printfT3(Teacher pT)
{
cout<<pT.age<<endl;
pT.age = 45; //只会修改pT变量 ,不会修改t1变量
}
void main()
{
Teacher t1;
t1.age = 35;
printfT(&t1);
printfT2(t1); //pT是t1的别名
printf("t1.age:%d \n", t1.age); //33
printfT3(t1) ;// pT是形参 ,t1 copy一份数据 给pT //---> pT = t1
printf("t1.age:%d \n", t1.age); //35
cout<<"hello..."<<endl;
system("pause");
return ;
}
3 引用的意义
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性
4 引用的本质
引用在C++中的内部实现是一个指针常量:
Type& name 《=》Type* const name
引用在实现上,只不过是把指针间接赋值成立的三个条件的前两步和二为一
5 引用的难点
1 当函数返回值为引用时
1)当函数返回值为引用时若返回栈变量,不能成为其它引用的初始值,不能作为左值使用。
2)若返回静态变量或全局变量,可以成为其他引用的初始值,即可作为右值使用,也可作为左值使用。
#include <iostream>
using namespace std;
int getAA1()
{
int a ;
a = 10;
return a;
}
//返回a的本身 返回a的一个副本 10
int& getAA2()
{
int a ; //如果返回栈上的 引用, 有可能会有问题
a = 10;
return a;
}
int* getAA3()
{
int a ;
a = 10;
return &a;
}
void main1101()
{
int a1 = 0;
int a2 = 0;
a1 = getAA1();
a2 = getAA2(); //10
int &a3 = getAA2(); //若返回栈变量 不能成为其它引用的初始值
printf("a1:%d \n", a1);
printf("a2:%d \n", a2);
printf("a3:%d \n", a3); // *a3
cout<<"hello..."<<endl;
system("pause");
return ;
}
//变量是static 或者是 全局变量
int j1()
{
static int a = 10;
a ++ ;
return a;
}
int& j2()
{
static int a = 10;
a ++ ;
return a;
}
//若返回静态变量或全局变量
// 可以成为其他引用的初始值
// 即可作为右值使用,也可作为左值使用
void main1112()
{
int a1 = 10;
int a2 = 20;
a1 = j1();
a2 = j2();
int &a3 = j2();
printf("a1:%d \n", a1);
printf("a2:%d \n", a2);
printf("a3:%d \n", a3);
system("pause");
}
//--- 函数当左值
//返回变量的值
int g1()
{
static int a = 10;
a ++ ;
return a; //
}
//返回变量本身 ,
int& g2()
{
static int a = 10;
a ++ ;
printf("a:%d \n" , a);
return a;
}
void main()
{
// g1() = 100;
//11 = 100;
g2() = 100; //函数返回值是一个引用,并且当左值
g2();
int c1 = g1(); //函数返回值是一个引用,并且当右值
int c2 = g2(); //函数返回值是一个引用,并且当右值
//a = 100;
system("pause");
}
2 指针引用
#include "iostream"
using namespace std;
struct Teacher
{
char name[64];
int age;
};
int getTe(Teacher **myp )
{
Teacher *p = (Teacher *)malloc(sizeof(Teacher));
if (p ==NULL)
{
return -1;
}
memset(p, 0, sizeof(Teacher));
p->age = 33;
*myp = p; //
return 0;
}
//指针的引用而已
int getTe2(Teacher* &myp)
{
myp = (Teacher *)malloc(sizeof(Teacher));
myp->age = 34;
return 0;
}
void main()
{
Teacher *p = NULL;
//getTe(&p);
getTe2(p);
printf("age:%d \n", p->age);
system("pause");
}
3 常引用
1)在C++中可以声明const引用,const Type& name = var;const引用让变量拥有只读属性 。
2)Const & int e 相当于 const int * const e;
3)普通引用 相当于 int *const e1;
void main()
{
//普通引用
int a = 10;
int &b = a;
//常量引用 :让变量引用只读属性
const int &c = a;
//常量引用初始化 分为两种
//1 用变量 初始化 常量引用
{
int x = 20;
const int& y = x;
printf("y:%d \n", y);
}
//2 用常量 初始化 常量引用
{
//int &m = 10; //引用是内存空间的别名 字面量10没有内存空间 没有方法做引用
const int &m = 10;
}
cout<<"hello..."<<endl;
system("pause");
return ; }
8 函数扩展
1 inline内联函数
1)C++中推荐使用内联函数替代宏代码片段,C++中使用inline关键字声明内联函数
2)必须inline int myfunc(int a, int b)和函数体的实现,写在一块
3) 内联函数由编译器处理,直接将编译后的函数体插入调用的地方
宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程
4) C++编译器不一定准许函数的内联请求!
5)现代C++编译器能够进行编译优化,因此一些函数即使没有inline声明,也可能被编译器内联编译.
6) C++中内联编译的限制:不能存在任何形式的循环语句 ;不能存在过多的条件判断语句;函数体不能过于庞大;不能对函数进行取址操作;函数内联声明必须在调用语句之前.
2 函数重载(Overroad)
1)用同一个函数名定义不同的函数,当函数名和不同的参数搭配时函数的含义不同
2) 函数重载至少满足下面的一个条件: 参数个数不同; 参数类型不同; 参数顺序不同
3 默认参数
函数默认参数的规则
只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值.