IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++--------------->第八天,C++关键字、异常处理、转化函数、智能指针 -> 正文阅读

[C++知识库]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的空间是否被释放掉了,若释放了,返回真;若没释放,返回假。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:15:53  更:2021-07-24 11:18:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 0:07:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码