抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

重载函数+函数模板


目录

一、C++变量的存储期

存储期,即变量在内存中的存储周期。其又可分为静态存储期和动态存储期。

静态存储方式:在程序运行中分配固定的空间,程序结束后释放。(static)
动态存储方式:在程序运行中动态的分配空间。(形参、变量、函数调用的保护和恢复现场等)

C++变量的存储类别

四个类别:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)。

  1. auto

函数中的局部变量,不用static修饰,默认auto,即动态的分配存储空间。

1
2
3
4
5
int f(int a)
{
auto int b,c;
……
}
  1. static

局部变量定义为 static 时,系统分配静态空间,当变量调用结束时,保留原值而不释放空间,下次调用时该值依旧存在,且可以操作。

与一般的auto变量的区别在于,被调用结束后空间不释放。静态变量仅在编译时赋值一次,以后再调用不再赋值。而auto变量随便赋值,每次都不保留。

注:

  • 变量应该在定义时初始化,否则自动赋0或null。而auto是随机数。
  • 在被一个函数调用结束后,虽然保留了原空间的值,但来自不同函数的调用是互相不可见的。即如果有另外一个函数调用它,又是一个全新的空间分配。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
int f()
{
static int a=1; //定义静态局部变量
a = a + 1;
return a;
}
int main()
{
cout<<f()<<endl; //输出 2;
cout<<f()<<endl; //输出 3; //原变量值在上一次调用结束后保持不变。
return 0;
}
  1. register(了解)

背景:上述的变量都是存放在内存中的,而存取变量需要时间。当需要大量、频繁的调用某一变量时,选择使用CPU寄存器存取会更快(系统对寄存器的存取速度高于内存)。如此可以提高效率。

如今系统有自动选择是否寄存器。

  1. extern

用于声明全局变量,扩展全局变量的作用域。

  1. 同一个源文件下,例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int max(int a, int b)
    {
    return a>b?a:b;
    }

    int main()
    {
    extern int a,b; //(提前)引用全局变量 a,b
    cout<<max(a,b);
    }

    int a=16, b=-7; //定义全局变量 a,b
  2. 不同源文件下,两个文件使用同一个变量时,可以在一个文件中使用 extern 引用另一个文件定义好的变量。

注:如果不想被外部文件引用可以使用 static修饰变量。

二、内置函数——inline

内置函数,又称内联函数、内嵌函数。

背景:一般的程序执行并调用外部函数时,需要保存当前主调函数跳转去执行外部函数,需要保存现场,执行完后又需要恢复现场(即中断),如此是需要耗费时间的。为了节省时间,提高效率。C++的内置函数,是把函数放在主调函数中,和主调函数一起执行的。

具体实现:与一般的功能函数无异,仅在声明时需在开头加 inline 关键字。例如:

1
2
3
4
inline int max(int a, int b)
{
return a > b ? a : b;
}

注:为了避免主调函数过长,仅建议规模小(很简单的功能函数)而使用频繁的函数作为内置函数。

三、重载函数

重载函数,即函数参数个数、参数类型和参数顺序三者中必须至少有一种不同,函数返回值可同可不同的同名函数。
例如:

1
2
3
int max( int a, int b );
int max( int a, int b, int c );
double max(int a, double b ,float c);

四、带默认参数的函数

  1. 实参与形参的结合按从左至右的顺序,即有指定默认值得参数必须放在形参列表得最右端。

    1
    2
    void func(int a, int c=10, double d); //不可
    void func(int a, double d, int c=10); //可
  2. 一个函数不可以同时是重载函数又是有默认参数的函数。

  3. 在调用有默认参数函数前必须定义好默认参数。

指针

指针只是一个地址,为什么要定义基类型??eg:int *p;char *p;
答:不同的数据类型在计算机系统中的存储方式和所占字节数不同,而指针只是一个地址,只是指向某个存储空间,但是读取数据的时候读取多少呢?noone knows。这时,数据类型站出来了,它说它知道 已经知道不同的数据类型占不同大小的空间,所以用数据类型来定义指针,在读取的时候系统就能够知道要读取多少数据。

深入底层它不香吗?就这??好好学微机和计组

函数指针

1
2
3
4
5
6
7
8
//定义
int max(int a, int b);
int (*p)(int ,int ); //(*p)的括号不能省略
p=max;
//使用
int a,b,m;
cin>>a>>b;
m=p(a,b);

const指针

  1. 指向常量的指针变量

格式:const 类型名 * 指针变量名

用指向常量的指针变量只是限制了通过指针变量改变它指向的对象的值。

指针数组

指针数组:即数组每个元素都是用来存指针的。
定义:类型名 * 数组名[数组长度]

eg:int * p[4];

合理利用,是个好东西。

小记:p=&array[i] //将数组array第i个元素的地址给p.

指针使用小结简记

变量定义 含义
int *p[4] 指针数组
int (*p)[4] 一般的数组,p是数组首地址的指针变量
int * p() p为函数名,函数返回类型为int型地址
int (*p)() p为指向函数的指针
int **p 指针的指针
int const *p p是常指针,其值固定不变
还有 ……

引用

介绍
c++引用,即引向一个已存在的对象。俗称“别名”,类似指针,但比指针受到的限制更多。

C++ 引用 vs 指针

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。而指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

使用

引用只有声明,没有定义。即先定义一个变量,然后声明一个引用去指代这个变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
void swap(int & x, int & y ){ //定义引用
int temp;
temp=x;
x=y;
y=temp;
}

int main(int argc, char *argv[]) {
int a=23,b=45;
swap(a,b);
cout<<a<<"\n"<<b <<endl;
return 0;
}

引用还可作为返回值使用。

枚举

1
2
3
4
5
6
7
//定义
enum color{red,yellow,blue,black};
//使用
```c++
color co1,co2;
co1=red;
co2=co1(2);

使用次数=0

函数模板——template

函数模板,即建立一个通用函数,其函数类型和形参类型不具体指定,通过一个虚拟的类型来代表(也可称为泛型)。使用template关键词声明模板
例如:

1
2
3
4
5
6
7
//模板声明,T为类型参数。typename也可改写为 class.
//类型参数可以有多个 <typename T1, typename T2>
template <typename T>
T max(T a, T b)
{
return a > b ? a : b;
}

与重载函数的区别:重载函数是一个函数名多个函数,可以相对地理解为单一功能函数;函数模板是一个函数名一个模板对应多个不同参数类型功能需求的函数,是一个通用函数。

面向对象程序设计

在面向对象的程序设计中,除了主函数,其他的函数几乎都是出现在类里,通过类调用函数。程序的基本构成是类,程序面向的是类和对象。面向对象设计更利于开发更大规模的程序。

四个特点:抽象、封装、继承和多态性。

类class

类是对象的抽象,即类是虚的,对象是实的。
类是设计图纸上的设计,对象是根据设计做出来的实物。

成员函数的代码不占用对象的存储空间

  • 类的成员函数是公用的,即无论实例化了多少个对象,这些对象使用的函数都是相同的,公用的,并没有生成新的函数。
  • 类的内存大小,取决于类中声明的成员变量,与成员函数无关。

构造函数

  1. 同定义的一个类额多个对象之间可以相互赋值。如: Time t1; Time t2=t1;

  2. 参数初始化表初始化数据成员

格式:类名::构造函数名([参数表])[:成员初始化表]{}

1
2
3
4
5
6
7
8
9
class Box{
private:
int height;
int width;
int length;
public:
Box(int h, int w, int l):height(h),width(w),length(l){ //使用参数初始化表
}
};

就是直接用成员变量自己赋值

  1. 类的默认构造函数只有一个。可以是无参的构造函数或全指定了默认值的构造函数,二者不可同时出现,否则报错。

  2. 构造函数同样适用——上述 带默认参数的函数

常对象 和 常对象成员

常对象

定义常对象 类名 const 对象名(参数);

将函数定义为常函数 类型名 函数名()const;

  1. 常对象只能调用它的常函数,普通函数不可;常对象可以正常调用常函数。
  2. 常函数可以访问常对象中的数据成员,但依旧不可以对它们进行修改。
  3. 常函数不可以调用非常函数

注:当常对象的某个变量确实需要修改时,可以使用 mutable关键字,则常函数就可以正常的修改它。

在类中定义了常数据成员,则只能直接初始化或使用构造参数(通过参数初始化表)来初始化。

汇总小表

数据成员 非const的普通成员函数 const成员函数
非const数据成员 可以引用,也可以改变值 可以引用但不可以改变值
const数据成员 可以引用,但不可以改变值 可以引用,但不可以改变值
const对象 不允许引用 可以引用但不可以改变值

静态成员

被static修饰的成员。
静态成员是类层面的一部分。供类的其他函数和类的其他对象使用,是“公共”的。

静态数据成员

  1. 静态数据成员可以初始化,但只能在类体外初始化,且不能用参数初始化表。
  2. 可以用类名引用静态数据成员,也可以通过对象来引用数据成员。

静态成员函数

  1. 在类外调用静态成员函数时要使用 类名::函数名
  2. 静态成员函数没有this指针。即静态成员函数不可以访问非静态成员。

友元

关键字 friend 。定义为 friend 的函数或类为友元函数或友元类。
友元的作用:突破private的壁垒,访问类的私有成员。

使用:想要使用某一个类的私有成员,在该类中声明用 friend声明一下即可。

例如普通函数声明为友元函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Box{
private:
int height;
int width;
int length;
public:
Box(int h, int w, int l):height(h),width(w),length(l){ //使用参数初始化表
}
friend void display(Box &b);//声明
};

void display(Box &b){
cout<<b.height<<"\t"<<b.width<<endl;
}
int main(){
Box b(1,2,3);
display(b);//调用
return 0;
}

注:其他如友元成员函数也是如此,只需将类名带上即可。

析构函数

析构函数——清场人员,only one。

不反回任何值,没有函数类型,没有函数参数。

使用

1
2
3
4
5
6
7
8
class Box{
private:
int height;
int width;
int length;
public:
~Box(){};
};

几个对象的构造函数和析构函数调用顺序:先构造的后析构,后构造的先析构。

对象指针

对象都可用指针。

对成员函数使用指针,函数返回值类型作为指针的定义类型。

使用格式:&类名::成员函数名,例如:

1
2
3
4
5
6
7
8
class Time{……};
void Time::getTime(){}

int main(){
void(Time:: *p)(); //定义指向Time类的成员函数的指针变量p
p=&Time::getTime;//使p指向Time的函数getTime()
return 0;
}

这部分有点sao,pay attention。

运算符重载

运算符重载实质上是函数重载。其函数名就是 operator 运算符。其他与一般的函数一致。

大部分的运算符都能重载,除了这5个:.*::sizeof?:

  1. 运算符重载函数作为类的成员函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Complex{
public:
//简写
Complex operator + (Complex &c2);
Complex(int a, int b):real(a),imag(b){
};
private:
int real;
int imag;
};
Complex Complex::operator +(Complex &c2){
return Complex(real+c2.real,imag+c2.imag);
}
  1. 作为友元函数
1
2
3
4
5
6
7
8
9
10
11
12
13
class Complex{
public:
//简写
friend Complex operator + (Complex &c2);
Complex(int a, int b):real(a),imag(b){
};
private:
int real;
int imag;
};
Complex operator +(Complex &c1, Complex &c2){
return Complex(c1.real+c2.real,c1.imag+c2.imag);
}

虚基类


输入输出流(I/O Stream)

输入输出流:指若干个字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一个对象。

包括标准I/O、文件I/O和串I/O。

文件流

数据类型 描述
ofstream 该数据类型表示输出文件流,用于创建文件并向文件写入信息。
ifstream 该数据类型表示输入文件流,用于从文件读取信息。
fstream 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

头文件加<fstream>即可。

1
2
3
4
5
6
7
8
9
10
11
12
#include "iostream"
#include "fstream"
// 创建输入文件对象
ifstream infile;
ofstream outfile;
infile.open("myfile1.txt");
outfile.open("myfile2.txt");
float x,y;
infile>>x>>y;
outfile<<x<<'\t'<<y<<endl;
infile.close();
outfile.close();

注:本篇作为学习和复习C++课程的笔记和要点,内容不全,有错还请指出。😀😀

评论

Gitalk评论系统对接至Github Issue,随心评论🐾🐾.....