函数模板

函数模板还可以处理多个通用数据类型。 使用逗号分隔需定义的数据类型。

让我们来创建一个包含多种不同数据类型的参数(一个int和一个double)的函数,然后打印一个较小的值。

template <class T, class U>

正如你所看到的,这个模板声明了两个不同的通用数据类型T和U.

现在我们可以继续我们的函数声明:

template <class T, class U>
T smaller(T a, U b) {
  return (a < b ? a : b);
}

(a < b ? a : b)三元运算符用法,检查a<b,如果条件成立返回a,否则返回b

在main中,我们可以使用不同数据类型的函数:

template <class T, class U>
T smaller(T a, U b) {
  return (a < b ? a : b);
}

int main () {
  int x=70;
  double y=69.99;
  cout << smaller(x, y) << endl;
}

// 输出 69

最后输出是int型的,应为我们在调用函数模板的时候声明了int型函数。

类模板

就像我们可以定义函数模板一样,我们也可以定义类模板,允许类使用模板参数的成员作为类型。

使用相同的语法来定义类模板:

template <class T>
class MyClass {

};

就像函数模板一样,您可以使用逗号分隔的列表来定义多个通用数据类型。
我们创建一个类Pair,它将保存一对通用类型的值。

template <class T>
class Pair {
 private:
  T first, second;
 public:
  Pair (T a, T b):
   first(a), second(b) {
  }
};

上面的代码声明了一个类模板Pair,带有两个泛型类型的私有变量,以及一个用于初始化变量的构造函数。
如果您在类的外部定义成员函数,则需要使用特定的语法,例如在单独的源文件中。

您需要在类名后面的尖括号中指定泛型类型。

例如,要在类的外部定义一个成员函数bigger(),使用以下语法:

template <class T>
class Pair {
 private:
  T first, second;
 public:
  Pair (T a, T b):
   first(a), second(b){
  }
  T bigger();
};

template <class T>
T Pair<T>::bigger() {
  // 此处省略
}

定义一个MyClass成员函数hello(),其中MyClass是一个模板类,hello()将输出Hi

template <class T>
void MyClass<T>::hello()
{
  cout << "Hi" << endl;
}

bigger()函数将返回两个成员变量的最大值。

template <class T>
class Pair {
 private:
  T first, second;
 public:
  Pair (T a, T b):
   first(a), second(b){
  }
  T bigger();
};

template <class T>
T Pair<T>::bigger() {
  return (first>second ? first : second);
}

模板类的对象

要创建不同类型的模板类的对象,请在尖括号中指定数据类型,就像我们在定义类之外的函数时所做的那样。

在这里,我们为整数创建一个Pair对象。

Pair <int> obj(11, 22);
cout << obj.bigger();
// 输出 22
我们也可以使用相同的类来定义一个double型的对象

Pair <double> obj(23.43, 5.68);
cout << obj.bigger();
// 输出 23.43

异常处理

处理用户输入操作时,异常处理特别有用。

例如,一个要求用户输入两个数字的程序,然后进行整除,你必须对0进行限制,防止用户在第二个数字的时候输入0。

int main() {
  int num1;
  cout <<"输入你的第一个数字";
  cin >> num1;

  int num2;
  cout <<"输入你的第二个数字";
  cin >> num2;

  cout <<"Result:"<<num1 / num2;
}

如果用户输入除0之外的任何数字,则该程序正常工作。

但是如果输入了0则会导致程序崩溃,所以我们需要对输入的数据进行处理。

模板特化

要为数据类型char指定不同的行为,我们将创建一个模板特化。

template <class T>
class MyClass {
 public:
  MyClass (T x) {
   cout <<x<<"不是char类型"<<endl;
  }
};

template < >
class MyClass<char> {
 public:
  MyClass (char x) {
   cout <<x<<"是char类型!"<<endl;
  }
};

首先,请注意,我们在模板<>的前面添加了一个空的参数列表。 这是因为所有类型都是已知的,并且这个特化不需要模板参数,但是仍然是类模板的特化,因此需要注意这一点。

但比这个前缀更重要的是类模板名称之后的char特化参数。 这个特化参数本身标识了模板类被特化的类型(char)。

在上面的例子中,第一个类是通用模板,第二个是特化。

下一步是声明不同类型的对象并检查结果:

int main () {
  MyClass<int> ob1(28);
  MyClass<double> ob2(5.18);
  MyClass<char> ob3('w3cschool');
}
/* 输出: 
28 - 不是char类型
5.18 - 不是char类型
w3cschool 是char类型!
*/

正如你所看到的,泛型模板为int和double所调用。 但是,我们的模板特化是为char数据类型调用的。

请记住,从泛型模板到特化没有成员“继承”,所以模板类特化的所有成员都必须自行定义。

异常

程序执行过程中出现的问题称为异常。

在C ++中,异常是程序运行时产生的错误的反应,例如试图除以零。
C ++异常处理基于三个关键字:try,catch和throw。

当问题出现时throw是用来抛出异常的。

int fatherAge = 18;
int sonAge = 38;
if (sonAge > fatherAge) {
  throw "你爸真年轻~";
}

上述代码中,当sonAge比fatherAge大的时候就会抛出异常。

在throw语句中,参数确定异常的类型。 这可以是任何表达式。 表达式结果的类型将决定抛出异常的类型。

捕捉异常

try标识将激活用于检测异常的代码块。 接下来是一个或多个catch块。 catch关键字表示在引发特定异常时执行的代码块。

可以生成异常的代码被try / catch块包围。

您可以通过设置关键字catch后面的括号中显示的异常声明来捕获哪种类型的异常。

try {
  int fatherAge = 18;
  int sonAge = 38;
  if (sonAge > fatherAge) {
   throw 666;
  }
} 
catch (int x) {
  cout<<"你确定这是你爸?"<<x;
}

//输出 "你确定这是你爸? 666"

try块引发异常,然后catch块处理它。

错误代码666是一个整数,它出现在throw语句中,所以它会导致int类型的异常。

可能会列出多个catch语句来处理各种异常,以防try块引发多个异常。

异常处理

处理用户输入时,异常处理特别有用。

例如,一个程序要求用户输入两个数字,然后进行整除,为了确保被除数不为0,你就需要用异常处理。

int main() {
  int num1;
  cout <<"输入第一个数字:";
  cin >> num1;

  int num2;
  cout <<"输入第二个数字:";
  cin >> num2;

  cout <<"结果:"<<num1 / num2;
}

如果用户输入除0外的任何数字,程序将正常运行。

但是当用户在第二个数字的时候输入了0,则程序会崩溃

如果第二个数字等于0,我们需要抛出异常。

int main() {
  int num1;
  cout <<"输入第一个数字:";
  cin >> num1;

  int num2;
  cout <<"输入第二个数字:";
  cin >> num2;

  if(num2 == 0) {
   throw 0;
  } 

  cout <<"结果:"<<num1 / num2;  
}

如果第二个数字输入为0,这段代码将会抛出一个int型的异常:0。

现在我们需要使用try / catch块来处理抛出的异常。

int main() {
 try {
  int num1;
  cout <<"输入第一个数字:";
  cin >> num1;

  int num2;
  cout <<"输入第二个数字:";
  cin >> num2;

  if(num2 == 0) {
   throw 0;
  } 

  cout <<"结果:"<<num1 / num2; 
 }
 catch(int x) {
  cout <<"请勿输入0!";
 }
}

上述代码将会避免出现当num2为0时导致程序崩溃的问题,同时会抛出异常。

在我们的例子中,我们只捕获整数类型的异常。 可以指定你的catch块处理在try块中抛出的任何类型的异常。可以通过在catch的括号之间添加一个省略号(...)实现。

try {
  // 要执行的代码
} catch(...) {
  // 用来处理异常的代码
}

引入文件

另一个有用的C++功能是读取和写入文件的能力。这需要标准的C++库fstream。

fstream中定义了三种新的数据类型:

ofstream:输出文件流,创建信息并将其写入文件。

ifstream:输入从文件中读取信息的文件流。

fstream:一般文件流,具有ofstream和ifstream功能,允许它创建,读取和写入信息到文件。

要在C++中执行文件处理,头文件iostream和fstream必须包含在C ++源文件中。

#include <iostream>
#include <fstream>

打开文件

必须先打开一个文件,然后才能读取或写入文件。

可以使用ofstream或fstream对象来打开文件进行写入。

我们打开一个名为“w3cschool.txt”的文件,并写下一些内容:

#include <iostream>
#include <fstream>
using namespace std;

int main() {
  ofstream MyFile;
  MyFile.open("w3cschool.txt");

  MyFile << "hellow W3cSchool";
}

上面的代码创建一个名为MyFile的流对象,并使用open()函数在文件系统上打开“w3cschool.txt”文件。 如您所见,使用相同的流输出操作符来写入文件。

如果指定的文件不存在,打开的功能会自动创建。

关闭文件
当你完成对一个文件的操作后,可以使用成员函数close()关闭它。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
  ofstream MyFile;
  MyFile.open("w3cschool.txt");

  MyFile << "hellow W3cSchool";
  MyFile.close();
}

引入文件

您也可以使用ofstream对象的构造函数直接提供文件的路径并打开,而不是调用open函数。

#include <fstream>
using namespace std;

int main() {
  ofstream MyFile("w3cschool.txt");

  MyFile << "哇!666666";
  MyFile.close();
}

在某些情况下,例如当您没有文件权限时,可能会打开失败。

is_open()成员函数检查文件是否可以被访问。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
  ofstream MyFile("w3cschool.txt");

  if (MyFile.is_open()) {
   MyFile << "hellow W3cschool";
  }
  else {
   cout << "抱歉,文件无法访问";
  }
  MyFile.close();
}

文件打开模式

可以通过设置open函数的第二个参数定义打开文件的模式。

可以通过"|"设定多个模式。

例如,要以写入模式打开文件并截断它(如果已经存在),请使用以下语法:

ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

从文件读取

您可以使用ifstream或fstream对象从文件读取信息。

#include <iostream>
#include <fstream>
using namespace std;

int main () {
  string line;
  ifstream MyFile("w3cschool.txt");
  while ( getline (MyFile, line) ) {
   cout << line << '\n';
  }
  MyFile.close();
}

getline函数从输入流中读取字符并将其放入字符串中。

最后修改:2022 年 12 月 05 日
如果觉得我的文章对你有用,请随意赞赏