做网站推广 需要ftp,工商网站如何做实名,网页制作培训总结,wordpress 上传类型一.思想过渡 前言#xff1a;明确地说#xff0c;学了C语言就相当于学了 C 的一半#xff0c;从C语言转向 C 时#xff0c;不需要再从头开始#xff0c;接着C语言往下学就可以#xff0c;所以我强烈建议先学C语言再学 C。 1.面向过程与面向对象
从“学院派”的角度来…一.思想过渡 前言明确地说学了C语言就相当于学了 C 的一半从C语言转向 C 时不需要再从头开始接着C语言往下学就可以所以我强烈建议先学C语言再学 C。 1.面向过程与面向对象
从“学院派”的角度来说C 支持面向过程编程、面向对象编程和泛型编程而C语言仅支持面向过程编程。就面向过程编程而言C 和C几乎是一样的所以学习了C语言也就学习了 C 的一半不需要从头再来。
面向过程POP
以过程(Procedure)为中心的编程方式按照计算机执行的步骤按从上到下顺序设计程序
面向对象OOP
以对象 Object为核心的编程范式对象是类(Class)的实例类中包括了数据的定义和对数据的操作方法
2.类和对象
C是一门面向对象的编程语言理解 C首先要理解**类Class和对象Object**这两个概念。
C 中的类Class可以看做C语言中结构体Struct的升级版。结构体是一种构造类型可以包含若干成员变量每个成员变量的类型可以不同可以通过结构体来定义结构体变量每个变量拥有相同的性质。
C 中的类也是一种构造类型但是进行了一些扩展类的成员不但可以是变量还可以是函数通过类定义出来的变量也有特定的称呼叫做“对象”。
#include stdio.h//通过class关键字类定义类
class Student{
public://类包含的变量char *name;int age;float score;//类包含的函数void say(){printf(%s的年龄是 %d成绩是 %f\n, name, age, score);}
};int main(){//通过类来定义变量即创建对象class Student stu1; //也可以省略关键字class//为类的成员变量赋值stu1.name 小明;stu1.age 20;stu1.score 92.5f;//调用类的成员函数stu1.say();return 0;
} C语言中的 struct 只能包含变量而 C 中的 class 除了可以包含变量还可以包含函数。display() 是用来处理成员变量的函数在C语言中我们将它放在了struct Student外面它和成员变量是分离的而在 C 中我们将它放在了 class Student 内部使它和成员变量聚集在一起看起来更像一个整体。 注意对于熟悉 C 的读者这段代码并不规范请忽略这一细节主要是从C到C过渡。 结构体和类都可以看做一种由用户自己定义的复杂数据类型在C语言中可以通过结构体名来定义变量在 C 中可以通过类名来定义变量。不同的是通过结构体定义出来的变量还是叫变量而通过类定义出来的变量有了新的名称叫做对象Object。
在 C 中通过类名就可以创建对象即将图纸生产成零件这个过程叫做类的实例化因此也称对象是类的一个实例Instance。有些资料也将类的成员变量称为属性Property将类的成员函数称为方法Method。
二.命名空间
1.原因
一个中大型软件往往由多名程序员共同开发会使用大量的变量和函数不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过没有问题时将它们结合到一起就有可能会出现命名冲突。
例如小李和小韩都参与了一个文件管理系统的开发它们都定义了一个全局变量 fp用来指明当前打开的文件将他们的代码整合在一起编译时很明显编译器会提示fp重复定义Redefinition错误。
为了解决合作开发时的命名冲突问题C引入了命名空间的概念
namespace Li{ //小李的变量定义FILE* fp NULL;
}
namespace Han{ //小韩的变量定义FILE* fp NULL;
}2.语法格式
namespace 是C中的关键字用来定义一个命名空间语法格式为
namespace name{//variables, functions, classes //在这里面可以定义自己使用的任意变量、类、对象、函数
}name是命名空间的名字它里面可以包含变量、函数、类、typedef、#define 等最后由{ }包围。
使用变量、函数时要指明它们所在的命名空间。以上面的fp变量为例可以这样来使用
Li::fp fopen(one.txt, r); //使用小李定义的变量 fp
Han::fp fopen(two.txt, rb); //使用小韩定义的变量 fp::是一个新符号称为域解析操作符在C中用来指明要使用的命名空间。
除了直接使用域解析操作符还可以采用 using 关键字声明
using Li::fp;
fp fopen(one.txt, r); //使用小李定义的变量 fp
Han :: fp fopen(two.txt, rb); //使用小韩定义的变量 fpusing 声明以后的程序中如果出现了未指明命名空间的 fp就使用 Li::fp但是若要使用小韩定义的 fp仍然需要 Han::fp。
using 声明不仅可以针对命名空间中的一个变量也可以用于声明整个命名空间
using namespace Li;
fp fopen(one.txt, r); //使用小李定义的变量 fp
Han::fp fopen(two.txt, rb); //使用小韩定义的变量 fp在 using 声明后如果有未具体指定命名空间的变量产生了命名冲突那么默认采用命名空间 Li 中的变量。
3.标准命名空间
C是在C语言的基础上开发的早期的 C 还不完善不支持命名空间没有自己的编译器而是将 C 代码翻译成C代码再通过C编译器完成编译。这个时候的 C 仍然在使用C语言的库stdio.h、stdlib.h、string.h 等头文件依然有效此外 C 也开发了一些新的库增加了自己的头文件。
和C语言一样C 头文件仍然以.h为后缀它们所包含的类、函数、宏等都是全局范围的。后来 C 引入了命名空间的概念计划重新编写库将类、函数、宏等都统一纳入一个命名空间这个命名空间的名字就是std。
理论上可以发现对于不带.h的头文件所有的符号都位于命名空间 std 中使用时需要声明命名空间 std对于带.h的头文件没有使用任何命名空间所有符号都位于全局作用域。这也是 C 标准所规定的。
下面是一个完整使用C头文件和命名空间的例子
#include iostream
#include string
/*如果在这里使用using namespace std; 那么代表这整个.cpp的文件都是std下的这对于我们平时练习一个的.cpp文件没有区别
但如果是在多个.cpp文件构成的项目中或者一个.cpp文件类需要用到多个命名空间时还是写在函数内部比较好*/
int main() {//声明命名空间stdusing namespace std;//定义字符串变量string str;//定义 int 变量int age;//从控制台获取用户输入cin str age;//将数据输出到控制台cout str 已经 age 岁了 endl;return 0;
} 将 std 直接声明在所有函数外部这样虽然使用方便但在中大型项目开发中是不被推荐的这样做增加了命名冲突的风险我推荐在函数内部声明 std。
三.操作转变
1.输入与输出
在C语言中我们通常会使用 scanf 和printf来对数据进行输入输出操作在编写 C 程序时如果需要使用输入输出时则需要包含头文件iostream它包含了用于输入输出的对象例如常见的cin表示标准输入、cout表示标准输出、cerr表示标准错误。
cout 和 cin 都是 C 的内置对象而不是关键字。C 库定义了大量的类Class程序员可以使用它们来创建对象cout 和 cin 就分别是 ostream 和 istream 类的对象只不过它们是由标准库的开发者提前创建好的可以直接拿来使用。这种在 C 中提前创建好的对象称为内置对象。
使用 cout 进行输出时需要紧跟运算符使用 cin 进行输入时需要紧跟运算符这两个运算符可以自行分析所处理的数据类型因此无需像使用 scanf 和 printf 那样给出格式控制字符串。
2.布尔类型
C语言并没有彻底从语法上支持“真”和“假”只是用 0 和非 0 来代表。这点在 C 中得到了改善C 新增了bool类型布尔类型它一般占用 1 个字节长度。bool 类型只有两个取值true 和 falsetrue 表示“真”false 表示“假”。
遗憾的是在 C 中使用 cout 输出 bool 变量的值时还是用数字 1 和 0 表示而不是 true 或 false。但你也可以使用 true 或 false 显式地对 bool 变量赋值。 注意虽然我们平时写C语言代码时习惯了bool类型但是在标准的只有C语言的IDE中如果运行包含bool类型的代码是会报错的C语言并不支持bool类型只不过我们平时用的都是.cpp文件格式写的是C语言所以正确来说是C语言和C的结合版本那么C语言中的true和false怎么表示呢用int类型即可0表示真0表示假。 3.动态分配空间
在C语言中动态分配内存用 malloc() 函数释放内存用 free() 函数。如下所示
int *p (int*) malloc( sizeof(int) * 10 ); //分配10个int型的内存空间
free(p); //释放内存在C中这两个函数仍然可以使用但是C又新增了两个关键字new 和 deletenew 用来动态分配内存delete 用来释放内存。
用 new 和 delete 分配内存更加简单
int *p new int; //分配1个int型的内存空间
delete p; //释放内存如果希望分配一组连续的数据可以使用 new[]
int *p new int[10]; //分配10个int型的内存空间
delete[] p;和 malloc() 一样new 也是在堆区分配内存必须手动释放否则只能等到程序运行结束由操作系统回收。为了避免内存泄露通常new和 delete、new[] 和delete[]操作符应该成对出现并且不要和C语言中 malloc()、free() 一起混用。
四.const用法
1.修饰全局变量
关键字const用来定义常量如果一个变量被const修饰那么它的值就不能再被改变我们通常称这样的变量为常量。由于常量一旦被创建后其值就不能再改变所以常量必须在定义的同时赋值初始化后面的任何赋值行为都将引发错误。
我们知道在C语言中普通全局变量的作用域是当前文件但是在其他文件中也是可见的使用extern声明后就可以使用
代码段1源文件1
#include stdio.h
int n 10;
void func();
int main(){func();printf(main: %d\n, n);return 0;
}代码段2源文件2
#include stdio.h
extern int n;
void func(){printf(module: %d\n, n);
}不管是以C还是C的方式编译运行结果都是 module: 10 main: 10 在C语言中const 变量和普通变量一样在其他源文件中也是可见的。修改代码段1在 n 的定义前面加const限制如下所示
const int n 10; 修改后的代码仍然能够正确编译运行结果和上面也是一样的。这说明C语言中的 const 变量在多文件编程时的表现和普通变量一样除了不能修改没有其他区别。
但是如果按照C的方式编译将源文件后缀设置为.cpp修改后的代码就是错误的。这是因为 C 对 const 的特性做了调整C 规定全局 const 变量的作用域仍然是当前文件但是它在其他文件中是不可见的这和添加了static关键字的效果类似。虽然代码段2中使用 extern 声明了变量 n但是在链接时却找不到代码段1中的 n。 因为C中全局 const 变量的可见范围是当前文件所以如果在C中要使用同一项目下其他.cpp文件定义的全局变量被const修饰那么可以把const修饰的变量定义在头文件.h文件中通过引入头文件的方式来解决该类问题。 2.常量指针与指针常量
常量指针是指针指向的内容是常量可以有一下两种定义方式
const int * n;
int const * n;这是因为type和const是可以互换位置的需要注意以下两点
1.常量指针指向的值不能改变但是这并不是意味着指针本身不能改变常量指针可以指向其他的地址。2.常量指针说的是不能通过这个指针改变变量的值但是还是可以通过其他的引用来改变变量的值的。
指针常量是指指针本身是个常量不能在指向其他的地址写法如下
int *const n;需要注意的是指针常量指向的地址不能改变但是地址中保存的数值是可以改变的可以通过其他指向改地址的指针来修改。 小技巧区分常量指针和指针常量的关键就在于星号的位置我们以星号为分界线如果const在星号的左边则为常量指针如果const在星号的右边则为指针常量。如果我们将星号读作‘指针’将const读作‘常量’的话内容正好符合。int const * n是常量指针int *const n是指针常量。 3.修饰函数参数
const 通常用在函数形参中如果形参是一个指针为了防止在函数内部修改指针指向的数据该数据既可以是变量也可以是地址取决于你使用的是常量指针还是指针常量就可以用 const 来限制。
4.内存角度
先来看下面的两条语句
const int m 10;
int n m; 我们知道变量是要占用内存的即使被 const 修饰也不例外。m、n 两个变量占用不同的内存int n m;表示将 m 的值赋给 n这个赋值的过程在C和C中是有区别的。
在C语言中编译器会先到 m 所在的内存取出一份数据再将这份数据赋给 n而在C中编译器会直接将 10 赋给 n没有读取内存的过程和int n 10;的效果一样。C 中的常量更类似于#define命令是一个值替换的过程只不过#define是在预处理阶段替换而常量是在编译阶段替换。
C 对const的处理少了读取内存的过程优点是提高了程序执行效率缺点是不能反映内存的变化一旦 const 变量被修改C 就不能取得最新的值。
五.函数角度
1.内联函数
为了消除函数调用的时空开销C 提供一种提高效率的方法即在编译时将函数调用处用函数体替换类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数又称内嵌函数或者内置函数。
指定内联函数的方法很简单只需要在函数定义处增加 inline 关键字。 注意要在函数定义处添加inline关键字在函数声明处添加 inline 关键字虽然没有错但这种做法是无效的编译器会忽略函数声明处的 inline 关键字。 内联函数的另一个最大用处是替换宏在C语言中我们置断宏是可以带参数的它在形式上和函数非常相似。不过不像函数宏仅仅是字符串替换不是按值传递所以在编写宏时要特别注意一不小心可能就会踩坑。如果我们将宏替换为内联函数情况就没有那么复杂了通过内联函数来解决宏的按值传递问题是一个常见的用法。
2.默认参数
C定义函数时可以给形参指定一个默认的值这样调用函数时如果没有给这个形参赋值没有对应的实参那么就使用这个默认的值。也就是说调用函数时可以省略有默认值的参数。如果用户指定了参数的值那么就使用用户指定的值否则使用参数的默认值。
//带默认参数的函数
void func(int n, float b1.2, char c){coutn, b, cendl;
}//为所有参数传值func(10, 3.5, #);//为n、b传值相当于调用func(20, 9.8, )func(20, 9.8);//只为n传值相当于调用func(30, 1.2, )func(30);注意 默认参数除了使用数值常量指定也可以使用表达式指定C规定默认参数只能放在形参列表的最后而且一旦为某个形参指定了默认值那么它后面的所有形参都必须有默认值。 3.函数重载
在实际开发中有时候我们需要实现几个功能类似的函数只是有些细节不同。例如希望交换两个变量的值这两个变量有多种类型可以是 int、float、char、bool 等我们需要通过参数把变量的地址传入函数内部。在C语言中程序员往往需要分别设计出三个不同名的函数其函数原型与下面类似
void swap1(int *a, int *b); //交换 int 变量的值
void swap2(float *a, float *b); //交换 float 变量的值
void swap3(char *a, char *b); //交换 char 变量的值
void swap4(bool *a, bool *b); //交换 bool 变量的值 但在C中这完全没有必要。C 允许多个函数拥有相同的名字只要它们的参数列表不同就可以这就是函数的重载Function Overloading。借助重载一个函数名可以有多种用途。 参数列表又叫参数签名包括参数的类型、参数的个数和参数的顺序只要有一个不同就叫做参数列表不同。 函数的重载的规则
函数名称必须相同。参数列表必须不同个数不同、类型不同、参数排列顺序不同等。函数的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为函数的重载。
4.函数重载优先级
C 标准规定在进行重载决议时编译器应该按照下面的优先级顺序来处理实参的类型
优先级包含的内容举例说明精确匹配不做类型转换直接匹配暂无说明只是做微不足道的转换从数组名到数组指针、从函数名到指向函数的指针、从非 const 类型到 const 类型。类型提升后匹配整型提升从 bool、char、short 提升为 int或者从 char16_t、char32_t、wchar_t 提升为 int、long、long long。小数提升使用自动类型转换后匹配整型转换从 char 到 long、short 到 long、int 到 short、long 到 char。小数转换从 double 到 float。整数和小数转换从 int 到 double、short 到 float、float 到 int、double 到 long。指针转换从 int * 到 void *。
C 标准还规定编译器应该按照从高到低的顺序来搜索重载函数首先是精确匹配然后是类型提升最后才是类型转换一旦在某个优先级中找到唯一的一个重载函数就匹配成功不再继续往下搜索。
如果在一个优先级中找到多个两个以及以上合适的重载函数编译器就会陷入两难境地不知道如何抉择编译器会将这种模棱两可的函数调用视为一种错误因为这些合适的重载函数同等“优秀”没有一个脱颖而出调用谁都一样。这就是函数重载过程中的二义性错误。 注意类型提升和类型转换不是一码事类型提升是积极的是为了更加高效地利用计算机硬件不会导致数据丢失或精度降低而类型转换是不得已而为之不能保证数据的正确性也不能保证应有的精度。类型提升只有上表中列出的几种情况其他情况都是类型转换。 六.extern与extern c
1.关键字extern
利用关键字extern根据作用域不同大概有两种作用 1.引用同一文件中的变量 #includestdio.hint func();
int main()
{
func(); //1
extern int num;
printf(%d,num); //2
return 0;
}
int num 3;
int func()
{
printf(%d\n,num);
}因为变量num在main函数后面如果按照过程顺序执行的话计算机不会知道num的值使用extern int num;后可以告诉计算机存在这个值往后面找. 2.引用同一项目下另一文件的变量或函数结合const修饰全局变量理解。
2.extern “c”
如果你在编写项目的过程中使用的是C和C混合编程考虑到对函数名的处理方式不同势必会造成编译器在程序链接阶段无法找到函数具体的实现导致链接失败。为了避免函数以不同的编译方式处理我们应该使其在main.cpp文件中仍以 C 语言代码的方式处理这样就可以解决函数名不一致的问题。
extern 是 C 和 C 的一个关键字但对于 extern C我们大可以将其看做一个整体和 extern 毫无关系。
extern C 既可以修饰一句 C 代码也可以修饰一段 C 代码它的功能是让编译器以处理 C 语言代码的方式来处理修饰的 C 代码。