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的空间是否被释放掉了,若释放了,返回真;若没释放,返回假。