Giskard

(一)C++初步认识

2019-01-27

C++概念

支持面向对象程序设计

支持泛型程序设计

功能强大的标准库

C++语言是C 语言的超集,是一个更好的C

ISO国际标准化组织批准ANSI C++为C++的标准

C++编译系统提供的头文件有两类:

一类是标准的C++库头文件,这些头文件不带“.h”;这种写法也适合标准的C库头文件,但是必须使用前缀字符“c”。(用cstring代替string.h)

另一类是非标准的C++库头文件,这些头文件带“.h”。在连接时,编译系统会根据头文件名自动确定连接哪一个库。

使用标准C++库时,在所有的include指令之后,需要加入语句:using namespace std;

名字空间

C++标准库中的类和函数是在名字空间std中声明的

名字空间可以消除那些因重名而导致的命名冲突

能在名字空间以外声明或定义的实体,同样也能在名字空间之内声明或定义。

一个名字空间由关键字namespace开始,通常后接一个标识符来标识名字空间。在名字空间开始和结束的地方分别用左右大括号标记。

添加using可以避免使用双冒号

namespace ns1
{
    int inflag;
}
namespace ns2
{
    int inflag;
}

ns1::inflag=2;  
//或者
using ns1::inflag;
inflag=2;

ns2::inflag=-3;

C++允许使用没有名字的名字空间

namespace
{
    int inflag;
}

由于名字空间没有名字,因此无法在其它文件中引用

无名名字空间内的成员的作用域为本文件从声明无名名字空间的位置开始到文件结束

C++的输入/输出

C++本身没有定义输入/输出操作,而是由一个I/O流类库提供的。流类对象cin和cout分别代表标准的输入设备和输出设备。它们在文件iostream声明。

在C++中输出操作可理解为将数据插入到输出流对象中,故称为插入操作。屏幕输出是标准输出操作。<<是输出运算符,也称插入运算符。

在C++中输入操作可理解为从输入流对象中提取数据,故称为提取操作。键盘输入是标准输入。>>是输入运算符,也称提取运算符。

C语言中常用#define命令来定义符号常量。在预编译时进行字符置换,又称宏替换

const int MaxLine =1000; //用const定义标识符常量时,一定要对其初始化

const常量与宏常量相比的优点:

const常量有数据类型,而宏常量没有数据类型

有些集成化的调试工具可以对const常量进行调试,但不能对宏常量进行调试

在C++中,如果函数调用的位置在函数定义之前,则要求在函数调用之前必须对所调用的函数作函数原型声明。

int max(int x,int y)若返回值为int,可以省去int

max(int x,int y)

int max(int,int)括号内为参数表

函数的重载

#include <iostream>
using namespace std; 
int add(int,int);
double add(double,double);
int main()
{  
    cout<<add(5, 10)<<endl;
       cout<<add(5.0, 10.5)<<endl;
       return 0;
}
int add(int x, int y)
{   
    return x+y;
}
double add(double a, double b)
{   
    return a+b;
}

重载函数的参数个数或类型必须至少有其中之一不同。不允许重载的函数只有返回类型不同。

函数模板

template<typename T>
T max(T a,T b)
{
       return(a>b)? a:b;
}

只适用于函数的参数个数相同而类型不同,且函数体相同的情况。

函数模板是对一组函数的描述,它以任意类型T为参数及函数返回值

函数模板不是一个实实在在的函数,编译系统并不产生任何执行代码

当编译系统在程序中发现有与函数模板中相匹配的函数调用时,便生成一个重载函数,该重载函数的函数体与函数模板的函数体相同,若为int,则生成

int max(int a,int b)
{
       return(a>b)? a:b;
}

该重载函数称为模板函数,它是函数模板的一个具体实例,只处理一种唯一的数据类型。

函数模板比函数重载更方便,程序更简洁。

定义函数模板时可以使用多个类型参数,每个类型参数前面只需加上关键字typename或class,用逗号分隔:

template<class T1, class T2>
T1 max(T1 a,T2 b)
{
       return (a>b) ? a : (T1)b;
}

有默认参数的函数

int area(int a=6);

C++可以给形参一个默认值,这样形参就不必一定要从实参取值了,形参为a,实参为area()中的变量

area(7); 即代入7

area();即代入6

实参与形参的结合是从左至右进行的,因此指定默认值的参数必须放在形参列表中的最右端

引用

对变量起另外一个名字 (别名alias),这个名字称为该变量的引用。

int a;
int &b=a;

a起了另外一个名字b

b并没有重新在内存中开辟单元,只是引用a的单元。a与b在内存中占用同一地址,即同一地址两个名字。

int a ;
int &b=a;
a=5;
b=10;
b=b+a;//20

int &b; 错误,没有具体的引用对象

对引用的操作就是对被引用的变量的操作。

引用类型变量的初始化值不能是一个常数。int &b = 5;错误!

一旦引用被声明,它就不能再指向其它的变量。

int a1, a2;
int &b=a1;
int &b=a2;   //错误!!!

对引用的初始化,可以用一个变量名,也可以用另一个引用

int a=3;
int &b=a;
int &c=b;

引用同变量一样有地址,可以对其地址进行操作,即将其地址赋给一指针。

int a,*p;
int &b=a;    //&是变量的引用
p=&b;         //&是变量的地址
*p=10;        //a=b=10

对const常量的引用使用如下方式:

int a=5;
const int &b=a;
b=3;         //错误!!
a=3;         //正确!!

这时b的值也是3,使用引用可以间接改变const类型的值

以下的声明是非法的

企图建立void类型的引用 void &a

企图建立引用的数组 int & a[6]

企图建立指向引用的指针 int & *p

指针与引用的区别

1、指针是通过地址间接访问某个变量,而引用是通过别名直接访问某个变量。

2、引用必须初始化,而一旦被初始化后不得再作为其它变量的别名。指针若不进行初始化,编译器不会报错。

引用的用途主要是用来作函数的参数或函数的返回值。

C语言传递参数的方法

1、将变量名作为实参

#include <iostream>
using namespace std;
void swap(int a,int b)
{
       int temp;
       temp=a;
       a=b;
       b=temp;
}
int main()
{
       int i=3,j=5;
       swap(i,j);
       cout<<i<<,<<j<<endl;
       return 0;
}
//结果3,5

2、 传递变量的指针

#include <iostream>
using namespace std;
void swap(int *p1,int *p2)
{
    int temp;
       temp=*p1;
       *p1=*p2;
       *p2=temp;
}
int main()
{
       int i=3,j=5;
       swap(&i,&j);
       cout<<i<<,<<j<<endl;
       return 0;
}

3、把变量的引用作为函数形参,即传送变量的别名

void swap(int &a, int &b)  //a,b是实参i,j的别名
{   
    int temp;
    temp=a;  
    a=b;   
    b=temp;
}
int main()
{   
    int i=3,j=5;
    swap(i,j);  //实参为变量
    cout<<i<<,<<j<<endl;
    return 0;
}  

#####引用和指针变量作为形参的区别

引用作为形参,实参是变量;指针变量作形参,实参是地址。

指针变量要另外开辟内存单元,其内容是地址;引用不是一个独立的变量,不单独占内存单元。

必须用指针运算符*来表示指针变量所指向的变量;而引用就代表该变量。

引用比指针更直观、方便、容易理解。

函数的返回值为引用类型

int a=4;
int& f(int  x)
{    
      a=a+x;
      return  a; 
}
int main()
{    
      int t=5;
    cout<<f(t)<<endl; //输出a=9
    f(t)=20;          //先调用,a=14,再赋值,a=20
      return 0; 
}

返回的变量的引用,这个变量必须是全局变量或静态局部变量,即存储在静态区中的变量。

函数作为一种程序实体,它有名字、类型、地址和存储空间,一般说来函数不能作为左值(即函数不能放在赋值号左边)。但如果将函数定义为返回引用类型,因为返回的是一个变量的别名,就可以将函数放在左边,即给这个变量赋值。

内联函数

调用函数需要一定的时间,如果有的函数需要频繁使用,则累计所用时间会很长,从而降低程序的执行效率。

C++提供一种提高效率的方法,即在编译时将所调用函数的代码嵌入到主函数中。这种嵌入到主函数中的函数称为内联函数(inline function,内置函数,内嵌函数)

内联函数是C++对C函数的扩充,是一种以空间效率换取时间效率的机制。

#include <iostream>
using namespace std;
inline int max(int a,int b)
{
      if(b>a)
          a=b;
      return a;
}
int main()
{
      int i=1;
      int j=2;
      int m=max(i,j);
}

相当于将max(i,j)改为

a=i;b=j;

if(b>a)

​ a=b;

m=a; 直接嵌入进主函数

关键字inline 必须与函数定义体放在一起才能使函数成为内联函数,仅将inline 放在函数声明前面不起作用。

inline与define有点相似

慎用内联

使用内联函数可以节省运行时间,但却增加了目标程序的长度

函数体内出现循环或递归等复杂的结构控制语句时,不适合定义为内联函数

一个好的编译器将会根据函数的函数体,自动取消不值得的内联

作用域运算符 ::

#include <iostream>
using namespace std;
float a=13.5;
int main() 
{
      int a=5;
      cout<<a<<endl;
      cout<<::a<<endl;
      return 0;
}

::a表示全局作用域中的变量a=13.5。

字符串

C++用一种更方便的字符串类型(string类型)定义字符串变量。string不是基本类型,是一个字符串类

定义字符串变量

string string1;
string string2=“China”; 

对字符串变量的赋值

string1=“Canada”;
string1=string2;

用赋值运算符实现字符串复制

string1=string2;  //与strcpy(string1,string2);相似    

用加法运算符实现字符串连接

string1=string1+string2;

用关系运算符(==,>,<,!=,>=,<=)实现字符串比较

字符串数组

string name[3]={“Zhang”,”Li”,”Wang”};

每一个字符串元素中只包含字符串本身的字符而不包括’\0’

动态分配/撤销内存(new/delete)

int* p = (int*)malloc(100*sizeof(int));

malloc仅仅是申请一块指定大小的内存,而不是创建对象

使用malloc必须指定需要开辟的内存空间的大小,而且其返回值为 void *类型,必须进行强制类型转换才能使其返回的指针指向具体的数据

int *p=new int;   //分配存放整数的空间

int *p=new int(3); //整数初值为3

int *p=new int[5]; //该数组有5个元素
Tags: C/C++