标准C++(四)

一、静态成员

静态成员变量

被static修饰过的类成员变量,叫静态成员变量,这种成员变量的特点是存储空间为bss段或data段,该变量只会被创建出一份,为所有类对象共享。
静态成员变量属于类,而不是某个类对象。静态成员变量的声明与定义:
在类静态成员变量仅仅是声明,定义、初始化必须在类外,定义时不再需要static。
类型 类名::成员名;

注意:静态成员变量依然受访问控制符的限制,private、protected权限的静态成员变量依然只能在类内访问,public权限的静态成员变量可以当全局变量使用。

注意:具有const属性的静态成员变量可以在类内设置初始值。

静态成员函数

被static修饰的类对象函数叫静态成员函数,这种成员函数的特点是没有隐藏的this指针,所以这种静态成员函数中不能直接访问成员变量、成员函数(但它依然算作类内,具有访问权限),但可以直接访问静态成员变量、静态成员函数。

静态成员函数的调用

1、通过类对象调用。
对象.函数名();
2、不使用类对象就可以调用。
类名::函数名(参数);
3、成员函数中可以直接调用静态成员函数。

静态成员函数的作用

静态成员函数可以作为类的接口,实现对类的管理。

常考面试题

C语言中static与C++中的static有什么区别?

二、单例模式

什么是单例模式

只能创建出一个实例对象的叫单例模式。

单例模式的应用场景

Windows系统的任务管理器
Linux/UNIX系统的日志管理
网站的访问计数器
服务端程序的连接池、数据池、线程池等。

获取单一对象的方法

1、定义全局变量(C语言),但不受控制。
2、专门实现一个类,把类的构造函数设置为私有,借助静态成员函数提供一个创建接口来获取唯一的类对象。

C++实现单例模式

1、禁止类的外部创建类对象,把构造函数设置为private。
2、类自己维护一个实例对象,使用静态指针或静态对象。
3、提供一个获取实例对象的方法,定义一个静态成员函数用于获取唯一的实例对象。

饿汉模式

将单例类的唯一实例对象定义为类的静态成员变量,当程序运行时,唯一的实例对象就已经创建完成。
优点:程序运行时就已经创建好实例对象,线程安全。
缺点:无论是否使用,总会创建,浪费内存。

懒汉模式

用静态成员指针来指向唯一的实例对象,只有真正调用获取单例对象静态接口时,实例对象才会被创建。
优点:什么时候用什么时候创建,节约内存。
缺点:当多个线程同时调用静态接口时,可能创建出多份。

练习1:分别以饿汉模式和懒汉模式一个单例类,同时要解决懒汉模式的线程不安全问题。

三、运算符重载

在C++中会把运算符当做函数来处理,当我们使用运算符时,编译器其实是把运算符翻译成函数,由于C++支持函数重载,所以C++中的运算符也是可以重载的,这样可以对类对象进行定制操作,从而简化操作、提高代码的可读性,如:string类就一个支持众多运算符的字符串类。

A a,b;
当对象支持+运算符时:a+b;
成员函数:
const A& operator+(const A& b);
全局函数:
const A& operator+(const A& a,const B& b);

四、双目运算符重载

双目录运算符的运算结果是一个临时对象,所以返回值应该是const。
成员函数:

const A& operator#(const A& b) const
{
    return 类(a参数#b参数);
}

全局函数:

const A& operator#(const A& a,const B& b)
{
    return 类(a参数#b参数);
}

注意:全局运算符函数中可能会访问到类的私有、保护的成员变量,C++提供的解决方案是把全局运算符声明为类的友元函数,那么在友元函数中就可以访问类的私有、保护类的成员。

友元:在类的外部某个函数中想访问类的私有、保护类成员,需要把函数声明为类的友元函数,但友元仅仅是朋友,它只有访问权没有拥有权(没有this指针)。

友元声明:把函数的声明写到类中一份,并在函数的声明前加伤friend关键字。

注意:友元函数不会与成员构成重载,因为它们不在一个作用域内,但依然可能会冲突。

五、输入输出运算符重载

1、cout 是ostream类型对象,cin 是istream类型对象。
2、当我们想让一种类方便使用 cout/cin 输入输出时就需要把它们的 <</>> 运算符进行重载。
3、根据双目运算符的解析规则,如果重载为成员函数,则函数的调用者为cin/cout,但我们无法到 ostream/istream类中修改代码,因此只能重载为全局函数。

ostream& operator<<(ostream& os const A a)
{
    
}
istream& operator>>(istream& is conat A a)
{

}

注意:在输入输出过程中,cin/cout会记录错误、状态标志,所以不能const属性。

六、赋值类型运算符重载

void operator=(const A& b)
{

}

1、注意赋值运算符的调用
A a = val; // 调用单参构造
a = b; // 调用赋值运算符

注意:一般不需要重写赋值运算符,类中有缺省的赋值运算符,当需要深拷贝时才需要显示实现。

七、单目运算符的重载

成员函数

[const] A operator#(void)[const]
{

}

全局函数

[const] A operator#([const] A& that)
{
    
}

前–/++

A& operator++(void)
{

}
A& operator++(A& that)
{

}

后–/++

A operator++(int)
{

}
A operator++(A& that,int)
{

}

注意:前自变与后自变的参数基本一致,唯一的区别是哑元

八、特殊运算符的重载

[] 下标运算符,重载了它类对象可以伪装成数组使用,STL模板库大多数容器都重载了它。

() 函数操作运算符,重载了它类对象可以伪装成函数使用。

*解引用运算符,-> 成员访问运算符,重载了它类对象可以伪装成指针使用,STL中的智能指针就是通过重载它们实现的。

new/delete 堆内存管理运算符:
1、C++默认的堆内存管理器速度比较慢,重载new/delete底就可以使用malloc/free提高运行速度。
2、当申请的内存比较小时可能会产生内存碎片,重载new之后可以扩大小字节块的内存,减小内存碎片产生的机率。
3、重载new和delete可以重载函数记录内存的使用信息,帮助解决内存泄漏的问题。

九、重载操作符的限制

1、只能重载为成员函数的运算符
[ ] ( ) -> *

2、只能重载为全局函数的运算符
<< >>

3、不能重载的运算符
:: 域限定符
. 直接成员访问符
? : 三目运算符
sizeof 字节长度运算符
typeid 类型信息运算符

4、重载运算符无法改变运算符优先级。

5、无法重载基本类的运算符。

6、不能改变运算符的参数个数。

7、无法发明新的运算符。

十、运算符重载的建议

1、重载运算符时要根据运算符的实际功能和意义来确定具体的参数、返回值是否需要const属性,返回值是引用或临时对象。

2、重载运算符要合乎情理,要以实际用途为前提。

3、重载运算符是为了让对象的操作更简单、方便,提高代码的可读性,而不是为了炫技。

4、重载运算符时要与运算符默认的功能、运算规则一直,不要有反人类的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值