9.12学习记录

一.

该函数模板中,调用的实参不能为两个不同的类型

/* 重要.cpp */
// Eg9-1.cpp
#include <iostream>
//注意一点,max与min使用的时候,容易引起冲突,如果写了下面这一行代码,则要改变函数模板名字,否则直接使用std::cout与std::endl
using namespace std;
/*
不要把这里的class与类的声明关键字class混淆在一起,虽然它们由相同的字母组成,但含义是不同的。
这里的class表示T是一个类型参数,可以是任何数据类型,如int、float、char等,或者用户定义的struct、enum或class等自定义数据类型。
*/
template <class T> T Min(T a, T b) { return (a < b) ? a : b; }
/*
为了区别类与模板参数中的类型关键字class,标准C++提出了用typename作为模板参数的类型关键字,同时也支持使用class。
比如,把min定义的template <class T>写成下面的形式是完全等价的:
*/
template <typename T> T myMin(T a, T b) { return (a < b) ? a : b; }

/*
模板实例化发生在调用模板函数时。当编译器遇到程序中对函数模板的调用时,
它才会根据调用语句中实参的具体类型,确定模板参数的数据类型,
并用此类型替换函数模板中的模板参数,生成能够处理该类型的函数代码,即模板函数。
当多次发生类型相同的参数调用时,只在第1次进行实例化。编译器只在第1次调用时生成模板函数,
当之后遇到相同类型的参数调用时,不再生成其他模板函数,它将调用第1次实例化生成的模板函数。
*/
int main() {
  double a = 2, b = 3.4;
  float c = 2.3, d = 3.2;
  cout << "2,3    的最小值是:" << Min<int>(2, 3) << endl; //显式调用
  cout << "2,3.4  的最小值是:" << Min(a, b) << endl;      //隐式调用
  cout << "'a','b'	  的最小值是:" << Min('a', 'b') << endl;
  cout << "2.3,3.2的最小值是:" << Min(c, d) << endl;
  cout << "2.3,3.2的最大值是:" << std::min(c, d)
       << endl; //引用命名空间内部的最小值函数
  cout << "2.3,3.2的最小值是:" << myMin(c, d) << endl; //更换class为typename
  // cout<<"2,'a'    的最小值是:"<<Min(2,'a')<<endl;
  // //报错,不同类型无法处理,请看9-3-1.cpp
  
  return 0;
}

 cout<<"2,'a'    的最小值是:"<<Min((int)a,2)<<endl;改成这样即可

二.map容器

"Map" 是一种常用的数据结构,它允许你存储键值对(key-value pairs)。在许多编程语言中,你都可以找到类似的实现。我将为你列举一些常见的编程语言及其对应的 map 容器库,并简要介绍如何使用它们。

  1. C++ - std::map

C++ 的标准库提供了一个 std::map 容器,你可以使用它来存储键值对。

#include <iostream>  
#include <map>  
  
int main() {  
    std::map<std::string, int> my_map;  
    my_map["apple"] = 1;  
    my_map["banana"] = 2;  
    my_map["cherry"] = 3;  
  
    std::cout << "Banana: " << my_map["banana"] << std::endl;  
  
    return 0;  
}
// 引入需要的头文件  
#include <iostream>     // 引入输入输出流库  
#include <map>          // 引入map容器库  
#include <string>       // 引入字符串库  
using namespace std;    // 使用标准命名空间,这样我们就可以直接使用如cout, cin等而不需要std::cout, std::cin等  
  
// 程序主函数  
int main(int argc, char const *argv[]) {  
  // 定义两个数组,分别存储员工姓名和工资  
  string name[] = {"张三", "李四", "王麻子"};  
  double salary[] = {1200, 2000, 1450};  
    
  // 定义一个map容器来存储员工的姓名和工资,其中key为员工姓名,value为员工工资  
  map<string, double> sal;  
  // 定义一个迭代器来遍历map容器  
  map<string, double>::iterator p;  
    
  // 使用循环将前面定义的员工姓名和工资插入到map中  
  for (int i = 0; i < 3; i++) {  
    sal.insert(make_pair(name[i], salary[i]));  
  }  
    
  // 插入额外的员工信息  
  sal["tom"] = 6156;  
  sal["bob"] = 5999;  
    
  // 输出所有的员工姓名和工资信息  
  for (p = sal.begin(); p != sal.end(); p++) {  
    cout << p->first << "\t" << p->second << endl;  
  }  
    
  // 提示用户输入要查找的员工姓名  
  string person;  
  cout << "输入查找人员的姓名:";  
  cin >> person;  
  int flag = 1;  // 定义一个标记,用于判断查找是否成功  
    
  // 在map中查找用户输入的员工姓名,并输出其工资信息  
  for (p = sal.begin(); p != sal.end(); p++)  
    if (p->first == person) {  
      cout << p->second << endl;  
      flag = 0;  // 查找成功,将标记设为0  
    }  
    
  // 如果查找失败,则输出提示信息  
  if (flag)  
    cout << "没查找到对应的结果!" << endl;  
  
  // 提示用户输入要删除的员工姓名  
  cout << "输入待删除的人员的姓名:";  
  cin >> person;  
  map<string, double>::iterator it;  
  it = sal.find(person);  // 在map中查找用户输入的员工姓名  
    
  // 如果查找成功,则删除该员工信息,并输出删除成功的信息  
  if (it != sal.end()) {  
    cout << "查找成功:" << (*it).first << ":" << (*it).second << endl;  
    sal.erase(it);  // 删除找到的员工信息  
    cout << "删除成功" << endl;  
  }  
    
  // 输出删除后的所有员工姓名和工资信息  
  cout << "删除后的结果为" << endl;  
  for (p = sal.begin(); p != sal.end(); p++) {  
    cout << p->first << p->second << endl;  
  }  
    
  return 0;  // 程序正常结束,返回0  
}

上面这个代码可能更易于理解

三.try示例

这段代码演示了C++中的异常处理机制,具体解释如下:

// Eg10-1.cpp  
#include <iostream>  // 引入输入/输出流库  
using namespace std;  // 使用标准命名空间,使得可以不必前缀std::来调用标准库的成员  
  
int main() {  // 主函数  
  cout << "1--before try block..." << endl;  // 输出“1--before try block...”并换行  
  
  try {  // 尝试执行代码块,如果发生异常,则会跳转到匹配的catch块处理  
    cout << "2--Inside try block..." << endl;  // 输出“2--Inside try block...”并换行  
    throw 10;  // 抛出一个整型异常,值为10  
    cout << "3--After throw ...." << endl;  // 这行代码不会被执行,因为throw会立即跳出try块  
  } catch (int i) {  // 捕获整型异常  
    cout << "4--In catch block1 ... exception..errcode  is.." << i << endl;  // 输出“4--In catch block1 ... exception..errcode  is..”和异常值i,并换行  
  } catch (char *s) {  // 捕获字符指针异常(这个catch块在这里不会被触发,因为没有抛出字符指针类型的异常)  
    cout << "5--In catch block2 ... exception..errcode is.." << s << endl;  // 输出“5--In catch block2 ... exception..errcode is..”和异常值s,并换行  
  }  
  
  cout << "6--After Catch...";  // 输出“6--After Catch...”  
}

注意:在try块中,一旦throw语句被执行,try块中的剩余代码将不会被执行。程序会直接跳到与抛出异常类型相匹配的catch块中。如果没有匹配的catch块,程序会终止。

// 引入输入/输出流库,使程序可以使用cin,cout等I/O功能  
#include <iostream>  
  
// 使用标准命名空间,使得可以不必前缀std::来调用标准库的成员  
using namespace std;  
  
// 定义一个名为temperature的函数,接受一个整数参数t  
void temperature(int t) {  
  
  // 如果t等于100  
  if (t == 100)  
    // 抛出一个字符串类型的异常,异常信息为"沸点!"  
    throw "沸点!";  
  // 否则如果t等于0  
  else if (t == 0)  
    // 抛出一个字符串类型的异常,异常信息为"冰点!"  
    throw "冰点!";  
  // 否则  
  else {  
    // 输出t的值,提示当前温度  
    cout << "temperatore=" << t << endl;  
  }  
}  
  
// 主函数,程序的入口点  
int main() {  
  try {  
    // 尝试调用temperature函数,传入参数0  
    // 如果发生异常,会进入catch块处理  
    temperature(0);   // L1  
    // 尝试调用temperature函数,传入参数10  
    temperature(10);  // L2  
    // 尝试调用temperature函数,传入参数100  
    temperature(100); // L3  
  } catch (char const *s) {  
    // 如果捕获到异常,输出异常信息  
    cout << s << endl;  
  }  
    
  // 主函数返回0,表示程序正常结束  
  return 0;  
}
#include <iostream>
using namespace std;
void temperature(int t) {
    try {
        if (t == 100)
            throw "It's at the boiling point.";
        else if (t == 0)
            throw "It reached the freezing point";
        else
            cout << "the temperature is OK..." << endl;
            throw t;
    }
    catch (int x) {
        cout << "temperature=" << x << endl;
    }
    catch (char const* s) {
        cout << s << endl;
    }
}
int main() {
    temperature(0);   // L1
    temperature(10);  // L2
    temperature(100); // L3

    return 0;
}

这两个程序就因为try的位置不同,而使得输出结果大不相同。

看下面的例子

// 引入iostream库,用于输入输出功能  
#include <iostream>  
  
// 使用std命名空间,使得我们可以直接使用iostream库中的成员,如cout,endl等  
using namespace std;  
  
// 定义一个名为handler的函数,它接受一个整数参数n,并可能抛出三种类型的异常:int,char和double  
void handler(int n) throw(int, char, double) {  
  
  // 如果n等于1,抛出一个整数类型的异常,值为1  
  if (n == 1)  
    throw n;  
  
  // 如果n等于2,抛出一个字符类型的异常,值为字符'x'  
  if (n == 2)  
    throw 'x';  
  
  // 如果n等于3,抛出一个双精度浮点数类型的异常,值为1.1  
  if (n == 3)  
    throw 1.1;  
}  
  
// 定义主函数main  
int main() {  
  
  // 输出"Before handler..."  
  cout << "Before handler..." << endl;  
  
  // 使用try块来包围可能抛出异常的代码  
  try {  
    // 调用handler函数并传入参数1,可能抛出异常  
    handler(1);  
  } catch (int i) {  
    // 如果抛出的是整数类型的异常,捕获并处理,输出"catch an integer..."  
    cout << "catch an integer..." << endl;  
  } catch (char c) {  
    // 如果抛出的是字符类型的异常,捕获并处理,输出"catch an char..."  
    cout << "catch an char..." << endl;  
  } catch (double d) {  
    // 如果抛出的是双精度浮点数类型的异常,捕获并处理,输出"catch an double..."  
    cout << "catch an double..." << endl;  
  }  
  
  // 主函数返回0,表示程序正常结束  
  return 0;  
}

如果你从函数handler中移除了throw(int, char, double),程序将无法编译并运行。这是因为在C++中,throw关键字用于声明函数可能会抛出的异常类型。如果你移除了这个声明,编译器将无法知道函数可能会抛出哪些类型的异常,因此会报错。

如果你希望函数不抛出任何异常,可以将throw()留空,这样编译器将认为该函数不会抛出任何异常。

void handler(int n) throw() {  
  // 函数实现  
}

如果你去掉了throw(int, char, double)这部分代码,程序仍然能够成功运行,那么可能是因为你没有在函数handler中实际抛出任何异常。在这种情况下,移除throw声明不会影响到程序的运行。

然而,如果你希望函数能够抛出异常并在调用该函数的地方捕获这些异常,那么你需要保留throw声明,并确保函数内部有相应的throw语句来抛出异常。

总之,如果你去掉了throw(int, char, double)这部分代码并且程序能够成功运行,可能是因为你在函数中没有实际抛出任何异常,或者你没有在程序中捕获这些异常。建议你仔细检查代码,确保异常处理机制的正确性和健壮性。

在C++中,如果子类和父类有同名的成员函数,程序将使用子类的成员函数。这被称为函数重写(function overriding),它是面向对象编程的一个重要特性。

如果在子类中需要调用父类的同名函数,可以使用作用域解析运算符 :: 来显式地指定使用父类的成员函数。

// Eg10-12.cpp
#include <iostream>
using namespace std;
class BasicException {
public:
  char *Where() { return "BasicException..."; }
};
class FileSysException : public BasicException {
public:
  char *Where() { return "FileSysException..."; }
};
class FileNotFound : public FileSysException {
public:
  char *Where() { return "FileNotFound..."; }
};
class DiskNotFound : public FileSysException {
public:
  char *Where() { return "DiskNotFound..."; }
};
int main() {
  try {
    //         .....  //程序代码
    throw FileSysException();
  } catch (DiskNotFound p) {
    cout << p.Where() << endl;
  } catch (FileNotFound p) {
    cout << p.Where() << endl;
  } catch (FileSysException p) {
    cout << p.Where() << endl;
  } catch (BasicException p) {
    cout << p.Where() << endl;
  }
  try {
    //        .....  //程序代码
    throw DiskNotFound();
  } catch (BasicException p) {
    cout << p.Where() << endl;
  } catch (FileSysException p) {
    cout << p.Where() << endl;
  } catch (DiskNotFound p) {
    cout << p.Where() << endl;
  } catch (FileNotFound p) {
    cout << p.Where() << endl;
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值