考核目标
1.熟悉C++的基本程序结构
2.自主学习并熟练掌握一种C++的集成开发环境Dev C++ 5.11的使用方法,见教材附录。
3.初步理解面向对象程序设计的思想
第一节 C++语言的发展简史
C++是由贝尔实验室1979年在C语言的基础上开发成功的。
C++兼容C语言,用C语言写的程序基本上可以不加修改地用于C++
C++对C的"增强"表现在两个方面:
(1).在原来面向过程的机制基础上,增强了C语言对类型的处理。
(2).增加了面向对象的机制。
C++语言是一种编译式(写完之后要编译成可执行文件再运行) 、通用的(通用性很强,适用于很多不同的操作系统)、大小写敏感的编程语言,完全支持面向对象的开发模式。
第二节 C++语言的特点
一.基本的输入/输出
cpp
#include<iostream>
using namespace std;
int main()
{ int a[10];
for(int i=0;i<10;i++)
cin>>a[i];
for (int i=0;i<10;i++)
cout<<a[i]<<" ";
cout<<endl;
}
C++环境:vscode里安装C/C++拓展、+GCC and Mingw-64 on Windows(编译工具)、配置好系统PATH、--->GCC \G++\GDB
部署好环境之后,可以直接在终端中使用命令行编译源码,编译完之后会在同一目录下生成exe文件,直接执行exe文件即可。注意的是:C的编译命令行是用的gcc ,有些情况下C++的某些命令与C是相同的,所以可以用GCC编译,但尽管 GCC 可以编译 C++ 代码,但默认情况下它不会自动链接 C++ 标准库(重点是那些不同于C的地方)。这是因为 GCC 主要是作为 C 语言编译器设计的。对于 C++ 程序,应使用 G++ 编译器,后者会自动处理 C++ 标准库的链接。
基本所有的C++程序在最开始必须要有这两条命令??↓
说明:
①标准输入:cin>>变量1>>变量2>>...>>变量n;
②)标准输出:cout<<表达式1<<表达式2<<...<<表达式n;
③使用标准输入cin及标准输出cout前,要在程序的最前面包含:
#include<iostream>//包含头文件:输入输出流
using namespace std;//使用标准命名空间?
④换行操作:用语句cout<<endl ;或cout<<"\n"
⑤当连续从键盘读取想要的数据时,以空格、制表符(Tab〉键或〈Enter〉键作为分隔符 。如果第一个字符是空格、〈Tab〉键或〈Enter〉键,则cin会将其忽略并清除掉,继续读取下一个字符
⑥ 用户自己定义的类型的数据 ,不能直接用">>"和"<<"进入输入/输出,必须对">>"和"<<"进行运算符重载后才可以使用。
头指令?没有分号就是伪指令
分号:
cin --->从键盘上输入,输入流
cout<< --->输出,cout<<end 1?? 换行符
二.头文件和命名空间
头文件
前面例题中 #include<iostream>
每个C++程序由头文件 和定义文件 组成。头文件作为一种包含功能函数、数据接口声明的载体文件 ,主要用于保存程序的声明,而定义文件用于保存程序的实现。头文件是用户应用程序和函数库 之间的桥梁和纽带。编译时,编译器通过头文件找到对应的函数库,进而把已引用函数的实际内容导出来代替原有函数,然后再进行翻译。
常用的头文件:
标准输入输出流:<iostream>
标准文件流:<fstream>
标准字符串处理函数:<string>
标准数学函数:<cmath>
除了可以使用系统提供的头文件外,程序员还可以定义自己的头文件。
命名空间
一个大型的程序不同模块中出现的标识符之间有可能发生重名现象,这就会引发错误。C++中为了避免名字定义冲突 ,特别引入了"命名空间 "的定义,即namespace 。命名空间的作用是为了消除同名引起的歧义。
在程序中使用标准程序库中的标识符 时,要写语句"using namespace std;"
三.强制类型转换运算符
当不同类型的量进行混合算术运算时,系统自动进行合理的类型转换,也可以强制转换类型
1.将一种数据类型转换成另一种数据类型
stati_cast<类型名>(表达式)
说明:staticast---可以省略不写
oneint2=static cast<int>(oneDouble);
oneint2=int(oneDouble);
oneint2=(int)oneDouble;//圆括号
oneint2=oneDouble //自动类型转换
2.const_cast<类型名>(表达式)
功能:将常量指针转化成非常量的指针 ,并且仍然指问原来的对象;或是将常量引用转换成非常量的引用,并且仍然指向原来的对象。
例:
int a=10,*q;const int ca=30;
const int *p=&a;//不能使用常量指针p修改a的值
g=const_cast<int *>(p)//不能q=p
*q=20//变量a的值变为20,不能形成*p=20
p=&ca;//ca的值不能修改
q=const_cast<int *>(p) //不能g=p
*q=40//*q的值为40,*p的值变成40
//变量ca的仍然是30
四.函数参数的默认值
◆C++中,可以在声明函数时为形参指定默认值。函数参数的默认值,在C语言里没有这个.
【例1-3】定义带默认值的函数
cpp
#include<iostream>
using namespace std;
void func(int a=11,int b=22,int c=33)
{ cout<<"a="<<a<<"b="<<b<<"c="<<c<<endl;}
int main()
{
func();
func(55);
func(77,99);
func(8,88,888);
retun 0:
}
◆C++语言规定,定义函数时,只能为函数最后面的连续 若干个参数设置默认值,且在调用处也只能缺省后面的连续 若干个实参。
例:判断以下函数声明 正确与否 //注意不是定义
void df1(int a=2,double b=3.0);//正确
void df2(int a,double b=3.0);//正确
void df3(int a=2, double b);
void f1(int a,int b=2,int c=3);//正确
void f2(int a=1,int b,int c=3);
void f3(int a=1,int b=2,int c) ;
◆C++语言规定,在函数调用处只能缺省后面的连续若干个实参,而且所有缺省的实参必须已经有默认值。
例:函数调用示例
函数声明:void func(int a,int b=2,int c=3)
函数调用:func(1,22,33);
func(); //错误
func(10,20);
func(5,,9); //错误
◆C++语言规定,指定默认值时不仅可以用常数,还可以用任何有定义的表达式 作为参数的默认值。例:假设给出如下的函数及变量声明:
int Max(int m,int n)
int a, b;
void func2(int x,int y=MAX(a, b),int z=a-b){...}
调用 func2(4);等价于func2(4,MAX(a,b),a-b);
func2(4,9);等价于func2(4,9,a-b);
func2(4,,10);错误
◆注意:函数参数的默认值可以写在声明函数的地方,也可以写在定义函数的地方,但不能在两个地方都写。函数声明 表示有 这么个函数了,函数定义 就是具体实现了。
函数声明:
int fun(int a, int b);
函数定义:
int fun(int a,int b)
{int c;
c=a+b;
return c;}
五.引用和函数参数的传递
1.引用:相当于给变量起了一个别名。别名的地址与引用变量的地址是一样的。程序中使用哪个名字都是允许的。
"引用"的定义格式:
类型名 &引用名=同类型的变量名;
例:int x=10;int &a=x //a就是x的一个引用,可以有多个引用
注意:
① 对象在引用前必须先初始化 ;
②声明中符号"&"的位置无关紧要
如int& a=x;int &a=x;int &a=x;等效
常引用的格式:
const 类型名 &引用名=同类型的变量名;
例:int x=10;
int &a=x; //a就是x的一个普通引用
const int &b=x; //b就是x的一个常引用
a=20; //则x=20,b=20
x=30; //则a=30,b=30
b=40: //错误
注意:不能通过常引用去修改其引用的变量的值
2.引用在函数中使用
引用作为函数的参数数
在函数在C++中,函数调用时参数的传递有两种方式:传值 和传引用 。传引用 是传递对象的首地址值 ,形参的改变就意味着实参的改变。
cpp
#include <iostream>
using namespace std;
void SVal(int a, int b)
{
int tmp;
tmp = a; a = b; b = tmp;
cout << "在SVal()函数中 :\t\ta=" << a << ",b=" << b << endl;
return;
}
void SRef(int &a, int &b)
{
int tmp;
tmp = a; a = b; b = tmp;
cout << "在SRef()函数中:\t\ta =" << a << ",b=" << b << endl;
return;
}
int main()
{
int a = 10, b = 20;
cout << "数据交换前:\t\ta=" << a << ",b=" << b << endl << endl;
SVal(a, b);
cout << "调用SVal()后:\t\ta=" << a << ",b=" << b << endl << endl;
a = 10; b = 20;
SRef(a, b);
cout << "调用SRef()后:\t\ta=" << a << ",b=" << b << endl;
return 0;
}
执行结果:
数据交换前: a=10,b=20
在SVal()函数中 : a=20,b=10
调用SVal()后: a=10,b=20
在SRef()函数中: a =20,b=10
调用SRef()后: a=20,b=10
◆引用作为函数返回值
返回引用的函数原型的格式如下:
数据类型&函数名(参数列表);
【例1-7】引用作为函数返回值
#include <iostream>
using namespace std;
int oneX=10,
int oneY=20;
int& refValue(int&x)//函数返回值是引用
{ return x;}
六.const与指针共同使用
当const与指针共同使用时,其书写的位置不同,语句含义也不同
1)如果唯一的const位于符号*的左侧,表示指针所指数据是常量数据不能通过本指针改变,但可以通过其他方式进行修改;指针本身是变量,可以指向其他的内存单元。
例: int a1=10,a2=20,*pa1=&a1;
*pa1=30;//正确,a1变成10
const int *pa2=&a2;//pa2所指的是常量,pa2是变
*pa2=40;//错误
pa2=&a1; //正确
2)如果唯一的const位于符号*的右侧,表示指针本身是常量,不能让该指针指向其他内存地址;指针所指的数据可以通过本指针进行修改。
例: int a1=10,a2=20:
int * const pa2=&a2;//指针变量pa2是常量
pa2=&a1;// 错误
*pa2=40;//正确
3)在符号*的左右各有一个const时,表示指针和指针所指数据都是常量,既不能让指针指向其他地址,也不能通过指针修改所指向的内容。
例: int a1=10,a2=20:
const int * const pa1=&a1;//数据和指针都是常量
pa1=&a2; // 错误
*pa1=30//错误
int const * const pa2=&a2;//数据和指针都是常量
pa2=&a1;// 错误
*pa2=40 //错误
记住const的修饰规则:const修饰其左侧的内容;如果const是本行的第一个标识符,则它修饰其右侧的内容。
const int *pa2=&a2;//pa2所指的是常量
int*const pa2=&a2;//指针变量pa2是常量
const int*const pa1=&a1;//数据和指针都是常量
int const * const pa2=&a2;//数据和指针都是常量
七.内联函数
对于需要频繁调用,且代码量少 的函数,可以将其定义为内联函数 。编译时,编译程序将整个函数体的代码复制 到调用该函数的位置。执行效率高一些。
定义内联函数的格式如下:
inline返回值类型函数名(形参表)
{函数体}
如果函数体中有循环语句和switch语句则通常不定义为内联函数。
八.函数的重载
函数重载 :C++允许为同一个函数定义几个版本,从而使一个函数名 具有多种功能,这称为函数重载 。只要分别为不同参数编制相应的函数体,就可以实现各自的功能。
例:函数重载的例子1
cpp
#include <iostream>
using namespace std;
// 声明2个整型参数的函数原型
int max(int, int);
// 声明3个整型参数的函数原型
int max(int, int, int);
int main() {
cout << max(36, 25) << "," << max(25, 39, 35) << endl;
}
// 定义2个整型参数的函数
int max(int m1, int m2) {
return (m1 > m2) ? m1 : m2;
}
// 定义3个整型参数的函数
int max(int m1, int m2, int m3) {
int t = max(m1, m2);
return max(t, m3);
}
实现函数的重载必须满足下列条件之一:
- 参数表中对应的参数类型不同;
- 参数表中参数个数不同;
- 参数表中不同类型参数的次序不同。
注意:
1)两个函数的名字和参数表都是一样的,仅仅是返回值类型不同(返回值类型相同不相同都不重要),则这两个函数不是重载的。
例:错误的重载函数
float add(int,float);
int add(int,float); //错误!
2)函数的参数采用引用 的,不能区分函数 ,则这两个函数不是重载的。
例:错误的重载函数
void print(double);
void print(double &)//错误!
3)函数调用可能会引发二义性,不能采用函数重载。
例:若定义了重载函数Sum(),如下所示:
int Sum(int a, int b, int c = 0);
int Sum(int a, int b);
则函数调用语句:Sum(l2);//调用会产生二义性
九.指针和动态内存分配
1.指针:即指针变量,该变量存储的是一个地址,是该指针所指对象的首地址。普通变量里存的是数,指针变量存的是地址。
cpp
int a =100,*pa=&a;
int s[10],ps=s;//指针ps指向数组s的首地址
2.动态内存分配
动态分配内存的一般格式为:
指针名=new 类型名;//分配
delete 指针名;//释放
对于delete 释放内存空间,c++里有严格的要求,当不再使用这个空间时,必须使用delete释放空间。若使用new运算符动态分配了一个数组,那么释放该数组时,语句如下:delete[]指针。
cpp
#include <iostream>
using namespace std;
int main()
{
double *p;//声明double型指针
p=new double[3];//分配3个double型数据的存储空间
for(int i = 0;i<3;i++)
cin>>*(p+i);
for(int j=0;j<3;j++)
cout<<*(p+j)<<" ";
delete []p;//释放空间
}
十.用string对象处理字符串
c语言用字符数组来处理字符串,例如:char name[]="C++程序";
c语言里没有string这个数据类型,c++中扩充了这个类型来处理字符串。
1.声明string对象
例如:
cpp
string str1; //声明string对象str1,值为空
string city="Beijing";//声明string对象并初始化
string str2=city;//使用字符串变量进行初始化
char name[]="C++程序";
string str3=name; //使用字符数组对string变量进行初始化
string citysf[]={"Beijing","Shanghai","Tianjing"};//声明string对象数组,每个数组元素都是字符串
说明:
1)使用string对象,必须**#include<string>**;
- string对象储存的是字符串的首地址,非字符串本身;sizeof(string)在32位的Dev C++中是4,在64位的Dev C++中是8。
2.string对象的操作
- string对象可以使用cin和cout进行输入和输出
cpp
string s1,s2;
cin>>s1>>s2;
cout<<s1<<","H<<s2<<endl
- string对象之间可以互相赋值,也可以用字符串常量和字符数组的名字对string对象进行赋值。
cpp
string s1,s2="OK";
s1="China";
s2=s1;//赋值后s2的内容与s1相同
- string对象之间可以用>、>=、==、<=、<、!=运算符进行比较。大小的判定标准是按照字典序进行的,并且是大小写相关的。
cpp
bool b;//C++新增了bool类型,该类型只有两个取值1或0,1表示"真",0表示"假"
string s1="China",s2="OK";
b=s1>s2;//变量b的值位0,O在C后面,所以O比C大
- 使用运算符"+"对字符串进行连接
cpp
string s1="China",s2="OK",s3=" ";
s1=s1+s3+s2;//连接后s1的内容 "China OK"
3.string类中的常用成员函数
略...
cpp
#include <iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
//empty()判断当前字符串是否为空
if(str.empty())
//length()返回当前字符串的长度
cout<<"str is NULL."<<",length="<<str.length()<<endl;
else
cout<<"str is not NULL."<<endl;
//append(const char*S)将字符串s连接到当前字符串的结尾处
str=str.append("abcdefg");
//size() 返回当前字符串的大小
cout<<"str is"<<str<<",size="<<str.size()<<endl;
cout<<"length="<<str.length()<<endl;
const char*p=str.c_str();//p指向了字符串str c_str()返回一个指向字符串的指针,字符串内容与本string串相同,用于将string 转换为const char*
cout<<"p="<<p<<endl;
//find(char ch,size type index) 返回字符ch在字符串中第一次出现的位置(从index开始查找),如果没有找到就返回-1
cout<<"find: "<<str.find("de",0)<<endl;//从str的第0查找字符串"de",成功,返回3
cout<<"find: "<<str.find("de",4)<<endl;//查找失败,返回-1对应的无符号数
//insert(int p ,const string &S);在P位置插入字符串S
string str1=str.insert(4,"123");//从str的第四位置插入"123"
cout<<str1<<endl;
return 0;
}
第三节 C++语言的程序结构
- C++程序以.cpp作为文件扩展名(C语言中是.c),C语言里由若干个函数构成,C++是若干个类和若干个函数构成。
- 程序中有且仅有一个主函数main(),程序从主函数的开始处执行,在主函数结束。程序的结束通常是遇到了以下两种情形之一:
- 1)在主函数中遇到了return语句。
- 2)执行到主函数的最后面的括号。
- 主函数中可以调用程序中定义的其他函数,但其他函数不能调用主函数,其他函数直接可以相互调用。
- C++程序中注释有两种形式:
- 1)从/*开始,到*/结束,如:/*.......*/
- 2)从//直到行尾,如: //.......
- C++的格式和C一样,都很自由,一行可以写几条语句,但也要注意错落有致,增加可读性。