第十一次复习

1.部分具体化

见代码:

#include<iostream>
using namespace std ;
template <class t ,class g   >
class nums 
{
    t a ;
    g b ;
public :
    nums( t k , g m  ) : a(k), b(m) {};
    t count ( ) ;

};
template class nums<double,double > ;
template<class t1> class nums <t1, int >  //部分具体化
{
    int k ; 
    
};
int main()
{
    nums<double ,double>*ptr ;
   // double c = l.count() ;
   // cout << c <<endl;
return 0 ;
}

原来具体化的模板是
template<> class nums <int 》
{} ;
部分具体化只是在《》里多加了不完全具体化的成员
调用时有限度
部分具体化》模板
其他优先度已经在上文提到过
2.多元化模板的体现
2.1 template《class t1 》class thing 《 t1 , t1* ,t1*》
2.2模板的嵌套

// queuetp.h -- queue template with a nested class
#ifndef QUEUETP_H_
#define QUEUETP_H_

template <class Item>
class QueueTP
{
private:
    enum {Q_SIZE = 10};
    // Node is a nested class definition
    class Node    //嵌套
    {
    public:
        Item item;
        Node * next;
        Node(const Item & i) : item(i), next(0) {}
    };
    Node * front;       // pointer to front of Queue
    Node * rear;        // pointer to rear of Queue
    int items;          // current number of items in Queue
    const int qsize;    // maximum number of items in Queue
    QueueTP(const QueueTP & q) : qsize(0) {}
    QueueTP & operator=(const QueueTP & q) { return *this; }
public:
    QueueTP(int qs = Q_SIZE);
    ~QueueTP();
    bool isempty() const
    {
        return items == 0;
    }
    bool isfull() const
    {
        return items == qsize;
    }
    int queuecount() const
    {
        return items;
    }
    bool enqueue(const Item &item); // add item to end
    bool dequeue(Item &item);       // remove item from front
};
// QueueTP methods
template <class Item>
QueueTP<Item>::QueueTP(int qs) : qsize(qs)
{
    front = rear = 0;
    items = 0;
}

template <class Item>
QueueTP<Item>::~QueueTP()
{
    Node * temp;
    while (front != 0)      // while queue is not yet empty
    {
        temp = front;
        front = front->next;
        delete temp;
    }
}

// Add item to queue
template <class Item>
bool QueueTP<Item>::enqueue(const Item & item)
{
    if (isfull())
        return false;
    Node * add = new Node(item);    // create node
    // on failure, new throws std::bad_alloc exception
    items ++;
    if (front == 0)             // if queue is empty
        front = add;            // place item at front
    else
        rear->next = add;       // else place at rear
    rear = add;
    return true;
}

// Place front item into item variable and remove from queue
template <class Item>
bool QueueTP<Item>::dequeue(Item & item)
{
    if (front == 0)
        return false;
    item = front->item;         // set item to first item in queue
    items --;
    Node * temp = front;        // save location of first item
    front = front->next;        // reset front to next item
    delete temp;                // delete former first item
    if (items == 0)
        rear = 0;
    return true;
}

#endif // QUEUETP_H_

看不下去了,有空再看吧

//主函数
//nested.cpp -- using a queue that has a nested class
#include <iostream>

#include <string>
#include "queuetp.h"

int main()
{
    using std::string;
    using std::cin;
    using std::cout;

    QueueTP<string> cs(5);
    string temp;

    while (!cs.isfull())
    {
        cout << "Please enter your name. You will be "
             << "served in the order of arrival.\n"
             << "name: ";
             getline(cin, temp);
             cs.enqueue(temp);
    }
    cout << "The queue is full. Processing begins!\n";

    while (!cs.isempty())
    {
        cs.dequeue(temp);
        cout << "Now processing " << temp << "...\n";
    }
    return 0;
}

3.将模板作为参数
声明 template《template《typename t》class thing 》
模板中的模板,这里把模板类thing作为参数
声明 crab《stack》abc ;//stack为类
4.在模板中使用友元函数
经过几个小时的努力,我终于搞了出来,见最后面

friend ostream& operator<< <T>(ostream& out, Complex& c); //注意观察,<T>的位置上
//这里用的输出友元注意t位置

友元尽量少用,在类模板里面,真的坑


5.非约束模板友元(只用类参)/约束模板友元(就是在类外有定义)

template <class T  >
class Complex 
{
    T a=10 ;
public :
   template <class a , class b>friend void show ( a& , b &) ;
};

就如字面意思一样,可以在类内定义非类模板的模板友元

下面是我的个人重测
我tm终于搞出来了,傻逼玩意

#include<iostream>
using namespace std ;
template <class oo>
void a () ; //友元具体化访问对应模板
template <class T  >
class Complex 
{
   
public :
     T a ;
    Complex (T kkk) : a(kkk) {} ;
   template <class oo>friend void show ( oo& ,  Complex<T> &) ; 
   //模块定义

};
template <class oo ,class T > //模块声明
void show ( oo & zz, Complex<T>& gg ) //对模板类的调用
{
    oo temp = zz*gg.a ; 
    cout<<temp <<endl;
}
int main()
{
    double k  = 10 ;
    Complex<double> oop = Complex<double> (10.9) ; 
    show<double , double > (k,oop) ; //对模板友元函数的使用
//透他的
return 0 ;
}

6.友元成员函数和友元类
声明友元类
friend class A ;

 class Complex 
{
   int a = 200 ;
   double  d = 100.23 ; 
   public : 
   friend class k ; //声明友元类
};
class  k {
    int c =20 ;
public :
    void  oo (Complex  k ) ; //定义友元类的对象,使其可以直接被使用
};
void k::oo(Complex k)
{
    cout<<k.a<<"ok"<<k.d<<endl; //可以直接访问私有成员
}
int main()
{
    Complex opp ;
    k  oop ;
    oop.oo(opp) ;
return 0 ;
}

引申
@1 互相友元类的使用
@2 共同友元函数(只能单独的函数友元)
7.嵌套类的访问权限
7.1 私有部分:包含类中可用,派生类中不可用,外部不可用
7.2 公有部分:包含类中可用,派生类中可用,外部可用
7.3 保护部分: 包含类中可用,派生类中可用,外部不可用


异常模块

类终于结束了,虽然留了一些难题,但是太过繁琐
1.先看几重简单的异常调用

#include<iostream>
#include <cstdlib>
#include<cfloat>
using namespace std ;

int main()
{
    cout<<DBL_MAX<<endl; //浮点数最大值
    cout<< "sfds"<<endl; 
    abort(); //缺点是调用后程序直接终止
return 0 ;
}

2.异常机制
核心表达式 try { … . .} ; catch {} ; throw ;
try语块内放可能出现异常的代码块,catch内放出现异常的处理办法,throw负责在函数中丢异常
简单的自定义和重载expection类

#include<iostream>
//#include<exception> //没有也能运作
using namespace std ;
struct myexception //这里定义了基本异常机制的运作方法
{
    const char* what() const throw () //重定义what(); 
    {return "my exception" ;}
};
double app (double a , int  j ) 
{ 
    if(j==0)
    throw myexception() ; //引发异常
    //throw "adsd" ; //为自定义版本
    return a*j ;
}
int main()
{
    int k = 0 , m = 6 ;
    try
    {
        app(m,k) ; 
    }
    catch(myexception&e) //接受异常
    {
        cout<<e.what() ; //显示异常原因
    }
   /** catch (const char * pd) //自定版本的catch
    {
        cout << pd <<endl ;
    }
    */
    
return 0 ;
}

大体结构就是如此
3.异常机制的深入exception
函数在寻找处理代码的过程中退出:寻找处理代码的过程与函数调用链刚好相反。当异常被抛出时,首先搜索抛出该异常的函数。如果没有找到匹配的catch子句,终止该函数,并在调用该函数的函数中继续寻找。如果还是没有找到匹配的catch子句,这个新的函数也被终止,继续搜索调用它的函数。以此类推,沿着程序的执行路径逐层回退,直到找到适当类型的catch子句为止。如果最终还是没能找到任何匹配的catch子句,程序转到名为terminate的标准库函数。该函数的行为与系统有关,一般情况下,执行该函数将导致程序非正常退出。
如果一段程序没有try语句块且发生了异常,系统会调用terminate函数并终止当前程序的执行。
上述过程就是栈解退的一部分原理

标准异常类和其他异常类
我们只能以默认初始化的方式初始化exception、bad_alloc和bad_cast对象,不允许为这些对象提供初始值。其它异常类型的行为则恰恰相反:应该使用string对象或者C风格字符串初始化这些类型的对象,但是不允许使用默认初始化的方式。当创建此类对象时,必须提供初始值,该初始值含有错误相关的信息。
异常的种类
1.
头文件stdexcept中的异常
(2)、exception头文件定义了最通常的异常类std::exception,它只报告异常的发生,不提供任何额外的信息。
exception总览
总览
(3)、new头文件定义了bad_alloc异常类型。
(4)、type_info头文件定义了bad_cast异常类型。

当执行一个throw时,跟在throw后面的语句将不再被执行

有关于栈解退
@1 throw返回不是终止函数的返回,而是回推查找函数的调用对象返回
@2 正常的函数返回上一级的对象,而throw返回上一级try{}块的返回地址并释放中间函数的自动类对象(栈内存释放)
@3 如果找不到try块最终返回给main函数 //调用terminate

异常特性
@1 throw给的是副本而不是引用
@2 如果放在多重继承里面
if{ 1,2,3}
try
catch{3,2,1}
要把顺序调过来
@3 补充: catch(…){代码}能处理所有异常,通常放在最后面确保所有异常被抓到
@4 函数指针及该指针所指的函数必须具有一致的异常说明。
@5 如果一个虚函数承诺了它不会抛出异常,则后续派生出来的虚函数也必须做出同样的承诺;在这里插入代码片
noexcept异常说明
关键字noexcept放在函数的末尾表示该函数不会抛出异常

在成员函数中,noexcept说明符需要跟在const及引用限定符之后,而在final、override或虚函数的=0之前

另一种表示:如果函数被设计为是throw()的,则意味着该函数将不会抛出异常:void f(int) throw();

noexcept说明符接受一个可选的实参,该实参必须能转换为bool类型:如果实参是true,则函数不会抛出异常;如果实参是false,则函数可能抛出异常。

关于throw或者noexcept中参数的再说明,里面如果是空则表示不会返回异常;如果为…则表示会返回任意异常;如果为特定异常类型则表示只会返回声明的异常

违反异常说明:
如果定义了noexcept()或者throw() 但是又在函数块里面使用了throw()语句,系统编译通过但是在运行时会直接调用terminate

进阶代码

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

const string egg="I not like this number,so I decided to refuse it.";

class non_44_error: public logic_error{
public:
    explicit non_44_error(const string &s=egg):logic_error(s){}
}; //和上面的一样,目的是重定义logic_error为新名称并赋予新的异常原因
//下面传参的时候就不用再次给string值了/char*值了
int main(){
    int input;
    while(1){
    try{
        cout<<"Please type in a number between 1 and 100."<<endl;
        cin>>input;
        if(!cin.good()){
            cin.clear();
            cin.ignore();
            throw invalid_argument("The input should be a number!");
        }
        if(input>=100)
            throw length_error("The input should be less than 100!");
        if(input<0)
            throw out_of_range("The input should be Non-negative number!");
        if(input==44)
            throw non_44_error(); //重定义异常的使用
        cout<<"Your input is "<<input<<". there isn't error\n";
    } catch(invalid_argument e){
        cout<<"*********************************"<<endl;
        cout<<"There is an invalid argument error occured"<<endl;
        cout<<"info:"<<e.what()<<endl;
        cout<<"*********************************"<<endl;
    } catch(length_error e){
        cout<<"*********************************"<<endl;
        cout<<"There is a length error occured"<<endl;
        cout<<"info:"<<e.what()<<endl;
        cout<<"*********************************"<<endl;
    } catch(out_of_range e){
        cout<<"*********************************"<<endl;
        cout<<"There is an out of range error occured"<<endl;
        cout<<"info:"<<e.what()<<endl;
        cout<<"*********************************"<<endl;
    } catch(non_44_error e){
        cout<<"*********************************"<<endl;
        cout<<"There is an error occured"<<endl;
        cout<<"info:"<<e.what()<<endl;
        cout<<"*********************************"<<endl;
    } catch(exception e){
        cout<<"*********************************"<<endl;
        cout<<"There is an undefined error occured"<<endl;
        cout<<"info:"<<e.what()<<endl;
        cout<<"*********************************"<<endl;
    }
        cout<<endl;
    }

    return 0;
}
输出:

Please type in a number between 1 and 99.
99
Your input is 99. there isn't any error

Please type in a number between 1 and 99.
1000
*********************************
There is a length error occured
info:The input should be less than 100!
*********************************

Please type in a number between 1 and 99.
-1
*********************************
There is an out of range error occured
info:The input should be Non-negative number!
*********************************

Please type in a number between 1 and 99.
d
*********************************
There is an invalid argument error occured
info:The input should be a number!
*********************************

Please type in a number between 1 and 99.
44
*********************************
There is an error occured
info:I don't like this number,so I decide to refuse it.
*********************************

exception的详细成员介绍和代码来源
除了自定义重命名类之外,其他调用都很简单
感觉除了标准异常外,其他异常就是扔给我们当模板玩玩的,只是省去了我们定义的过程,因为我们可以自己定义what内容
重新找了一张更具体的图
更好的表现
以上所有没有子类的异常全部为标准异常
也就是不带参数在直接catch() 的异常
看一个bad_expection的例子

#include <iostream>
#include <exception>
#include <stdexcept>
 
void my_unexp() { throw; }
 
void test() throw(std::bad_exception) //声明只会返回这种异常
{
    throw std::runtime_error("test"); //违背
}
 
int main()
{
    std::set_unexpected(my_unexp); //设置意外异常的处理方式
    try {
         test();
    } catch(const std::bad_exception& e) 
    {
        std::cout << "Caught " << e.what() << '\n';
    }
}

查了好久不知道为毛要设置,但是不设置就是运行时错误
//异常具体使用法则见网址,到此为止
笔记中找到了
见下一块

4.异常为何经常会迷失方向
当出现意外异常没有被捕获时,系统会默认调用terminate函数,terminate函数又会默认调用abort函数来终止程序
所以
可以自定义函数A (如上一篇代码所做的那样)//void类型无参,必须包含throw等操作
然后把set_terminate(A);放在开始让函数出现意外时默认调用A
以上的主要目的是修改未捕获终止调用函数
当函数出现意外异常(如与声明冲突)默认调用unexpected函数然后如果为定义后又会调用默认调用terminate函数
调用set_unexpect(A) ;
以上的主要目的是修改意外异常终止调用函数
都是重throw异常使其被catch
应该是由于优先度的原因所以要自己重设来捕获

5.补充一小点:关于new时的异常传递
小技巧,如果在try中捕获了带new的异常,可以全部回扔,然后在catch语块中将内存释放,然后二次回扔,在更高一介的地方进行异常的处理

关于类继承中的异常使用上文提到过,见第二篇代码中的调用方式
const char* s = “fdsdf” ;
class newexp : public runtime_error ;
{
newexp(const char* =s ) : runtime_error(s) ;
};
//调用时直接用新名字就好了


异常结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值