C++基础复习:各种基础函数——函数的重载、调用与声明、递归函数、内置函数、函数模板、变量存储方法类别、构造函数、析构函数、虚函数、this指针、

文章目录

  • 前言 * 1 函数的重载 * 2 函数的调用与声明 * 3 函数的递归调用 * 4 内置函数 * 5 函数模板 * 6 变量的存储方法与类别

  • 6.1 变量的存储方法 * 6.2 变量的存储类别

    1 * 7 内部函数和外部函数 2 * 8 构造函数 3 * 9 析构函数 4 * 10 this指针 5 * 11 虚函数 6 * 12 格式控制符 7

前言

我想总结这些常见的特殊函数类型

1 函数的重载

  • 函数的重载(founction overloading) 定义:C++允许同一函数名定义多个函数,而这些函数的参数个数和参数类型可以不相同,这就是函数的重载。 即对一个函数名重新赋予它新的含义,使得一个函数名可以多用。所谓重载,其实就是“一物多用”。

  • 不仅函数可以重载,运算符也可以重载。例如>>和<<,既可以作为移位运算符也可以作为输入输出流中的插入运算符和数据输入流中的提取运算符。

  • 函数的重载并不要求函数体(即花括号{}里的内容)是相同的。重载函数除了允许参数的类型不同以外,还允许参数的个数不同。

  • 重载函数的参数个数、参数类型或参数顺序三者中必须至少有一种不同,返回值类型可以相同也可以不同。

总结来说函数的重载就是函数名字是相同的。

2 函数的调用与声明

  • 如果被调用函数的定义出现在主调用函数之前,可以不必加以声明。
  • 函数声明的位置可以再调用函数所在的函数中,也可以在函数之外,只不过在函数之外的话其作用域是整个文件。

3 函数的递归调用

  • 在调用一个函数的过程中又出现直接或间接的调用该函数本身,成为函数的递归调用。包含递归调用的函数称为递归函数。

4 内置函数

  • 内置函数的目的或者作用就是为了提高程序的执行效率。省略了跳转的时间,直接顺序执行程序,节省了总程序的运行时间。
  • C++提供了一种提高函数调用效率的方法,在编译时将所调用的代码直接嵌入到主调用函数中,而不是将流程转出去。这种嵌入到主函数中的函数称为内置函数(inline founction),又称为内嵌函数/内联函数。
  • 指定内置函数只需要在函数首行左端加一个关键词inline即可。

5 函数模板

  • 函数模板(founction temple)即建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。

  • 函数模板的使用:

1template <typename T> //模板声明,其中T为类型参数,代表一个虚拟的类型名 2T max(T a, T b, T c) //定义一个通用函数,用T作虚拟的类型名 3{ 4 if(b>a) a=b; 5 if(c>a) a=c; 6 return a; 7} 8 9int main() 10{ 11 int x=1,y=2,z=3; 12 max(x,y,z); //调用模板函数,此时T被int取代 13} 14 15

6 变量的存储方法与类别

6.1 变量的存储方法

内存中供用户使用的存储空间的情况:

静态存储区 动态存储区

  • 静态存储

全局变量都存储在静态存储区,程序开始就给分配存储单元,直到程序执行完毕就释放这些空间。

  • 动态存储

存储:函数形式参数;函数中定义的变量(未加static声明);函数调用时的现场保护和返回地址等。

6.2 变量的存储类别

变量的存储类别(storage class)共有4种:自动的(auto),静态的(static),寄存器的(register),外部的(extern)。

自动变量(auto)
其实就是函数的形参和在函数中定义的变量(包括在复合语句中如for中定义的变量),都属于自动变量。也就是平常在变量定义时前边不加任何东西的话,系统就默认为是auto自动变量了。

属于一个动态的存储方式,在函数调用或复合语句结束时自动释放空间。其中auto和int的前后顺序随意,auto也可以省略,因此平常使用最多的就是auto了。声明方式:

1auto int a,b; 2 3
  1. 静态局部变量(static)

就是在函数中的局部变量在函数调用结束后不消失保留原值,即占用的存储单元不释放,在下一次调用该函数时,该变量仍保留上一次函数调用结束时的值。
典型例子:

1#include <iostream> 2using namespace std; 3int f(int a) //定义f函数,a为形参 4{ 5 auto int b=0; //定义b为自动变量 6 static int c=3; //定义c为静态局部变量 7 b=b+1; 8 c=c+1; 9 return a+b+c; 10} 11 12int main( ) 13{ 14 int a=2,i; 15 for(i=0;i<3;i++) 16 cout<<f(a)<<″ ″; 17 cout<<endl; 18 return 0; 19} 20 21

运行结果为
7 8 9
其中呢,c是静态局部变量,因此每回调用该函数时只是进行加操作而不赋初值3。

寄存器变量(register)
对于一些使用频繁的变量(比如这个函数中要执行10000次循环,每次循环都要引用某局部变量),则存取变量要花费不少时间,为了提高执行效率,C++允许将局部变量的值放在CPU的寄存器中,需要时直接从寄存器中取出参与运算,不必再到内存中去存取。实际很少用,了解即可。

外部变量(extern)
用extern是为了声明全局变量,以扩展全局变量的作用域。
比如这个已经定义好的全局变量没有在开头定义,在定义之前还想使用该变量就可以用extern来进行提前引用声明,以扩展该变量在程序文件中的作用域。

1int main() 2{ 3 extern int a,b;//对全局变量a,b作提前引用说明 4 c=a+b; 5 return 0; 6} 7 8int a=15,b=7;//定义全局变量 9 10

7 内部函数和外部函数

  • 内部函数: 如果一个函数只能被本文件中其他函数所引用,它称为内部函数。在定义时只需在函数名和函数类型前加static即可。

1static 类型标识符 函数名() 2 3
  • 外部函数: 函数定义左侧加extern表示此函数是外部函数,别的文件也可调用。

8 构造函数

  • 构造函数(constructor)是用来对类对象进行初始化的,是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,在建立对象时就自动执行了。它也可以定义在类外边。
  • 构造函数的名字必须与类名相同,而不能任意命名,以便编译器能自动识别并把其当做构造函数处理。
  • 利用构造函数是为了给对象中的数据成员函数赋初值。
  • 构造函数也可以重载,称为构造函数的重载。

9 析构函数

  • 析构函数(destructor)也是一个特殊的成员函数,作用与构造函数相反,名字是类名前加一个~符号,在C++中这是位取反运算符,从这点也可想到:析构函数是与构造函数作用相反的函数。
  • 当对象的生命周期结束时,会自动执行析构函数。
  • 析构函数的作用:析构函数的作用不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,为了释放资源。 它还可以被用来执行“用户希望在最后一次使用对象之后所执行的一些操作”。
  • 具体是四种情况:

(1)普通情况: 函数中定义对象了,函数被调用结束时会自动执行析构函数。
(2)函数中有静态(static)局部变量了,那再函数调用结束时这个对象并不会释放,因此也不会调用析构函数,只有当main函数结束或者调用exit函数结束程序时,才调用static局部对象的析构函数。
(3)定义了一个全局的对象,那在程序流程离开其作用域时(如main结束或调用exit时),才调用该全局的对象的析构函数。
(4)new新建了一个对象,那当用delete释放该对象时才会调用执行该对象的析构函数。

  • 析构函数由于没有函数参数所以是不能被重载的。它不返回任何值、没有函数类型、也没有函数参数。一个类只能有一个析构函数。

10 this指针

在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
一个实例:

1#include <iostream> 2 3using namespace std; 4 5class Box 6{ 7 public: 8 // 构造函数定义 9 Box(double l=2.0, double b=2.0, double h=2.0) 10 { 11 cout <<"Constructor called." << endl; 12 length = l; 13 breadth = b; 14 height = h; 15 } 16 double Volume() 17 { 18 return length * breadth * height; 19 } 20 int compare(Box box) 21 { 22 return this->Volume() > box.Volume(); 23 } 24 private: 25 double length; // Length of a box 26 double breadth; // Breadth of a box 27 double height; // Height of a box 28}; 29 30int main(void) 31{ 32 Box Box1(3.3, 1.2, 1.5); // Declare box1 33 Box Box2(8.5, 6.0, 2.0); // Declare box2 34 35 if(Box1.compare(Box2)) 36 { 37 cout << "Box2 is smaller than Box1" <<endl; 38 } 39 else 40 { 41 cout << "Box2 is equal to or larger than Box1" <<endl; 42 } 43 return 0; 44} 45 46

11 虚函数

  • 虚函数的作用是为了实现动态多态性:即同一类族中不同类的对象,对同一函数调用做出不同的响应。

  • 虚函数允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

  • 在声明虚函数时,在最左边加上一个关键字virtual,这样就把类中的函数声明成了虚函数。

1//Student是基类,Graduate是派生类,他们都有display这个同名的函数 2#include<iostream> 3#include<string> 4using namespace std; 5 6//------------声明基类Student------------- 7class Student 8{ 9public: 10 Student(int, string, float); //声明构造函数 11 virtual void display(); //声明虚函数 12protected: //受保护成员,派生类可以访问 13 int num; 14 string name; 15 float score; 16}; 17//Student类成员函数的实现 18Student::Student(int n,string nam, float s) //定义构造函数 19{num=n;name=nam;score=s;} 20 21void Student::display() //定义输出函数 22{cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\n\n";} 23 24 25//------------声明公用派生类Graduate--------------- 26class Graduate:public Student 27{ 28public: 29 Graduate(int, string, float, float); //声明构造函数 30 void display(); //定义与基类同名的函数 31private: 32 float wage; 33}; 34//Graduate类成员函数的实现 35Graduate::Graduate(int n,string nam, float s,float w):Student(n,nam,s),wage(w){} 36 37void Graduate::display() 38{cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\nwage:"<<wage<<endl;} 39 40 41//--------------主函数------------------- 42int main() 43{ 44 Student stud1(1001,"Wang",35.2); 45 46 Graduate grad1(2001,"Hang",74.2, 1500); 47 48 Student *pt=&stud1; 49 pt->display();//输出基类中数据 50 51 pt = &grad1; 52 pt->display();//输出派生类中数据 53 54 return 0; 55} 56 57

输出:
在这里插入图片描述

12 格式控制符

  • fixed,scientific,left,right,ws,setfill,setw,setprecision,这些是格式控制符,在使用时要加头文件#include <iomanip>

fixed是固定的意思、precision是精度的意思、setw是宽度的意思、setfill是填充的意思、ios是输入输出流、flags是标志的意思。
例如:

1double a=1.23456789; 2cout<<setprecision(4)<<a 表示输出数a的4位有效数字 3cout<<setiosflags(ios::fixed)<<setprecision(4)<<a 表示输出数a的4位小数 4double b=10; 5cout<<setfill('*')<<setw(8)<<b ;输出b的时候占8个位,不够的用*填充 6 7

输出:
在这里插入图片描述

代码交流 2021