C++--------------->第八天,C++关键字、异常处理、转化函数、智能指针

1 c++关键字


    1.1 explicit关键字
     作用:用来修饰类中的构造函数,防止单参数构造函数发生隐式类型转化
        (将基本数据类型转化成类类型)
    特点:1 只能修饰类中的构造函数
               2 explicit关键字只对一个参数的构造函数有效,如果构造函数的参数大于等于2,该关键字无效。(多参数的构造函数本身不会发生隐式类型转化)

#include <iostream>

using namespace std;

class demo
{
private:
    int a;
public:
    explicit demo(int x)
    {
        a=x;
        cout<<"demo(int x)------------------\r\n";
    }
    ~demo()
    {
        cout<<"~demo()----------\r\n";
    }
    void getint()
    {
        cout<<"a=="<<a<<endl;
    }
};

int main()
{
    //构造函数前未加explicit,1发生隐式类型转换
    //demo obj=1;//等价于demo obj1(1);demo obj=obj1;
    //构造函数前加explicit,只能用标准的定义方法去定义对象
    demo obj(2);
    obj.getint();//a=2

    return 0;
}


    1.2 override关键字
    若在基类中定义了虚函数,在子类中要对该虚函数实现重写,override关键字会帮你检查重写的虚函数名和基类的虚函数名是否一致,若不一致,编译会报错。
    注意:override要加在子类重写函数的后边

#include <iostream>

using namespace std;

class base
{
public:
    base()
    {
        cout<<"demo()-----------------\r\n";
    }
    ~base()
    {
        cout<<"~base()----------------\r\n";
    }
    virtual void func()
    {
        cout<<"base::func()----------\r\n";
    }
};

class sub:public base
{
public:
    sub()
    {
        cout<<"sub()-----------\r\n";
    }
    ~sub()
    {
        cout<<"~sub()-----------\r\n";
    }
    virtual void fun() override
    {
        cout<<"sub::func()-------------\r\n";
    }
};

int main()
{
    base *p=new sub;
    //p->func();

    return 0;
}


    1.3 final
    当你不希望某个类被继承,或者某个虚函数被重写,可以在类名后和虚函数后添加final关键字,添加后,此类就是一个final类(final类不能派生子类);此虚函数就是一个final虚函数(final虚函数不能被重写)

#include <iostream>

using namespace std;

class base
{
    virtual void func()
    {
        cout<<"base::func()--------\r\n";
    }
};

class sub:public base
{
    void func() final//func()在sub类中被重写,并且是最后一次被重写,所以sub的子类不能再重写func()了
    {
        cout<<"sub::func()---------\r\n";
    }
};

class sua final:public base//sua不能被继承
{
    void func()
    {
        cout<<"sua::func()--------\r\n";
    }
};

class sua1:public sua
{
    void func()
    {
        cout<<"sua1::func()--------\r\n";
    }
};

#if 0
class sub1:public sub
{
    void func()
    {
        cout<<"sub1::func-----------\r\n";
    }
};
#endif

int main()
{
    //sub obj;
    sua obj1;

    return 0;
}


    1.4inline
    inline表示内联,用它修饰类中的成员函数,被修饰的成员函数称为内联函数
   在c++中将内联理解成对函数的专有宏,是对C的函数宏的一种改进。对于常量宏,c++提供const替代,对于函数宏,c++用inline。使用函数宏比直接使用函数的系统开销小,所以通常建议将简短频繁调用的成员函数定义成内联函数。
    如何定义内联函数?在函数定义前加inline即可。
    
    内联函数的特点:
 1 函数体功能简单、代码简短、调用频繁
 2 内联函数是宏函数,是宏,使用时只需做宏替换,所以系统开销小。(内联函数在编译阶段被展开)
    注意:1 inline必须和函数的定义一起使用,如果只和函数声明放一起,则inline不起作用
               2 如果函数体代码过长或者函数体中有循环语句、if语句或switch语句或递归算法语句,那么不宜将此函数设计成内联函数。
              3 内联函数只是对编译器的一个建议,是否能真正内联,要看编译器 

#include <iostream>

using namespace std;

class demo
{
public:
    inline void func()  //内联函数
    {
        cout<<"demo::func()-----------\r\n";
    }
    void func1();//声明时不用加inline
};

inline void demo::func1()
{
  cout<<"demo::func1()----------\r\n";
}

int main()
{
    demo obj;
    obj.func();
    obj.func1();

    return 0;
}


2 异常处理---》C++语言提供的异常处理机制


    设备---》异常(告警)  异常的发起者---》硬件本身发起
                                         异常检测代码---》APP 检测  
                                         异常处理函数---》处理异常      
 c++异常处理机制由3部分构成:try异常检查----》throw抛出异常-----》catch捕获异常(异常处理)
      c++的标准异常处理机制:try-->throw-->catch
         try
    {//检查语句
          if(错误)
          throw 异常;
    }
    catch(异常类型)
    {
          处理异常;
    }
    catch(异常类型)
    {
          处理异常;
    }
    。。。。。。  

#include <iostream>
#include <stdexcept>

using namespace std;
int divtmp(int a,int b)
{
    if(0==b)
    {
        //异常,无效参数异常
        throw(invalid_argument("除数不能为零"));
    }
    return a/b;
}

int main()
{
    try
    {
        int a=10,b=0;
        int ret=divtmp(a,b);
        cout<<"ret="<<ret<<endl;
    }
    catch(invalid_argument&err)//err是C++标准库已经定义好的对象
    {
        //处理异常
        cout<<"err="<<err.what()<<endl;
    }
    catch(int err)  //整数异常
    {
        cout<<"err=====\r\n";
    }
    catch(...)     //其他异常
    {
        cout<<"no except--------\r\n";
    }
    return 0;
}


3 转化函数--->类型转化


  c++提供类型转化函数将一个类的对象转化成另一类型的数据,转化函数的实质
  就是运算符重载,只是重载的运算符不是内置的运算符,而是类名这个特殊的自定义类型
    种类:1 自定义转化函数
    格式:operator 类型名()
        {函数体;}
    转化函数的基本规则:1 转化函数只能是成员函数,无返回值,无参数
            2 不能将类类型转化成void类型,也不能转化成数组或函数类型
            3 转化函数通常定义成const形式,原因是它并不改变任何成员的值    

//自定义转化函数
class demo
{
public:
    demo(int a):x(a)
    {
        cout<<"demo(int a)----------\r\n";
    }
    ~demo()
    {
        cout<<"~demo()-------------\r\n";
    }
    operator int() const
    {
        return this->x;
    }
private:
   int x;
};

class demo1
{
public:
    demo1(int a,int b):x(a),y(b)
    {
        cout<<"demo1(int a,int b)----------\r\n";
    }
    ~demo1()
    {
        cout<<"~demo1()-------------\r\n";
    }
    operator double() const
    {
        return ((double)x/y);
    }
private:
   int x;
   int y;
};

int main()
{
    demo obj('a');
    int temp=obj;
    cout<<"temp="<<temp<<endl;

    demo1 obj1(3,5);
    double ret=10+obj1;
    cout<<"ret="<<ret<<endl;

    return 0;
}


               2 标准转化函数
      1 reinterpret_cast:可以做不同类型对象之间的转化,还能将指针类型转化成整数类型(可以做不同数据类型的指针和引用之间的转化)
     2 const_cast:可以将常指针或常引用转化成非常指针或非常引用
     3  static_cast:可以做基本数据类型之间的转化,也可以做具有继承关系的对象之间的转化
     4 dynamic_cast:可以做具有继承关系的指针或引用的转化
      

​
//标准转化函数
#if 0
int main()
{
    int a=10;
    const int *p=&a;//p是常指针
    cout<<"*p="<<*p<<endl;
    //*p=20;//error,*p的值不能修改
    int *q=const_cast<int *>(p);
    *q=20;
    cout<<"a="<<a<<endl;
    cout<<"*q"<<*q<<endl;

    return 0;
}
#endif
class base
{
public:
    virtual void func()
    {
        cout<<"base::func()----------\r\n";
    }
};

class sub:public base
{
public:
    void test()
    {
        cout<<"sub::test()-------------\r\n";
    }
};

int main()
{
    base obj1;
    sub obj2;
    base *p=&obj1;
    sub *q=&obj2;
    //基类的指针转化成派生类的指针
    sub *q2=static_cast<sub *>(p);
    sub *q3=dynamic_cast<sub *>(p);
    //q2->func();
    q2->test();

    //派生类的指针转化成基类的指针
    base *p2=static_cast<base *>(q);
    p2->func();

    sub *p3=dynamic_cast<sub *>(q);
    p3->func();

    return 0;
}

​


4 智能指针---》代表一个作用域


    本质:让智能指针的生命周期和堆内存的生命周期保持一致,释放智能指针的时候,自动将堆内存空间释放

       为什么要使用智能指针?C++没有自动内存回收机制,当我们写一个new语句时,一般也会立即把delete语句直接写上,但我们不能避免程序还未执行到delete时就跳转了或函数还没有执行到delete语句程序就返回了,那么此时就会造成内存泄漏。所以为了避免内存泄漏,引入了智能指针,因为智能指针就是一个类作用域,当超过了类的作用域时,系统会自动调用析构函数来释放内存资源。
     c++提供了4个常见的智能指针(类模板)?----》属于STL
auto_ptr:自动智能指针(已经被废弃)
shared_ptr:共享型智能指针,可以允许多个智能指针指向同一块内存空间,可以自动把堆内存空间释放(最后一个p没了,空间就被释放了)
weak_ptr:弱型智能指针,不能单独存在,必须和共享型智能指针一起使用(依附型智能指针),弱型智能指针的增加和消亡不会影响堆内存的释放

#include <iostream>
#include <memory>

using namespace std;

class demo
{
public:
    demo()
    {
        cout<<"demo()----------\r\n";
    }
    ~demo()
    {
        cout"~demo()------------\r\n";
    }
};

int main()
{
    shared_ptr<demo> p(new demo);//共享型智能指针
    shared_ptr<demo> q=p;
    cout<<q.use_count()<<endl;//有2个智能指针指向demo实例化的这块内存空间
    
    p.reset();//释放p
    cout<<q.use_count()<<endl;//有1个智能指针指向demo实例化的这块内存空间
    weak_ptr<demo> r=q;//依附型智能指针
    q.reset();//释放q
    if(r.expired())
    {
        cout<<"堆区空间已释放\r\n";
    }
    else
    {
        cout<<"堆区空间未释放\r\n";
    }
    
    return 0;
}


unique_ptr:独享型指针,同一时刻只能有一个独享型智能指针指向一块内存。  
    

#include <iostream>
#include <memory>

using namespace std;

class demo
{
public:
    demo()
    {
        cout<<"demo()--------\r\n";
    }
    ~demo()
    {
        cout<<"~demo()--------\r\n";
    }
    void func()
    {
        cout<<"demo::func()-------\r\n";
    }
};

int main()
{
    unique_ptr<demo> p(new demo);
    p->func();
    
    return 0;
}


reset():释放new申请的空间
expired():检测new的空间是否被释放掉了,若释放了,返回真;若没释放,返回假。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值