一, const
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1)
:_year(year),
_month(month),
_day(day)
{}
void Show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Show();
return 0;
}
还是拿日期类举例,看这段代码,d1调用Show()函数没有任何问题,但是,如果d1的类型变为 const Date d1,那结果将会如何呢?
编译器给出了如下的错误提示:传进去的 this 指针是const Date类型的,但是函数并没有 const
所以我们要改正只需要将Show()函数的形参改为const类型即可,那么以下这种改法可行吗?
void Show(const Date this)
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
答案当然是不行了,因为this是编译器默认处理的,我们无法干涉,正确的写法是这样的
void Show() const
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
在函数名后加一个 const,编译器发现这里有一个const的时候,就会默认的将 this指针定义为 const Date的类型
以下的几种调用可以执行吗
我们需要知道,const这个关键字其实是把我们的变量权限缩小,原本d1是可读可写的,加上const疑惑就成为只读的了
上面我们已经讨论过第一种是不可行的,我们无法用一个非const的函数来接收const类型的实参,因为我自己本身是只读的,传给了函数就变成了可读可写的,这属于权限放大,当然是不可以的,我自己都不能改变自己,别人凭什么可以改变我
不过,修改成第二种就可以了,传给函数以后权限并没有改变,依旧是只读的
第三个当然是可以的,非const参数传给非const函数,可以运行成功
第四个其实也是可行的,把一个可读可写的变量传给一个只读的函数,属于权限缩小,所以没问题
总结: 权限缩小没问题,权限放大不行哦
二、内联( inline )
这里我们不得不提起 C 语言中一个重要的东西 -- 宏
宏分为 宏函数 和 宏变量
宏的优缺点:
宏变量:代码复用性强(只改变宏就可以修改很多地方)
提高性能(在预处理阶段就进行了宏替换)
不方便调试
宏函数: 代码冗余
容易误用
可读性差
没有安全性检查
...
内联函数是在 c++中可以用来替换宏的机制
以inline修饰的函数叫做内联函数,编译时C++编译器会调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的的函数不适宜使用内联。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
3. inline必须函数定义放在一起,才能成为内联函数,仅将inline放在声明前是不起不作用的。
4. 定义在类内的成员函数默认定义为内联函数。
inline void Date::Show()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
注意:尽量用 const,enum,inline替换#difine
三、友元
在C++中友元函数允许在类外访问该类中的任何成员,就象成员函数一样,友元函数用关键字friend说明。
1. 友元函数不是类的成员函数。
2. 友元函数可以通过对象访问所有成员,私有和保护成员也一样。
友元函数其实大大的破换了封装性,所以建议一般不要使用,不过存在即有他的道理,这里举一个特殊的例子说明友元存在的必要性
重载输入输出运算符( << , >>)时,如果我们不使用友元函数,就必须定义成如下的样子
//重载运算符 >> <<
ostream& operator<<(ostream& out)
{
out<<_year<<"-"<<_month<<"-"<<_day<<endl;
return out;
}
所以,即使在这时也破坏了封装性,但是,权衡了利弊,我们选择提高可读性,所以使用友元函数
#include <iostream>
using namespace std;
class Date
{
public:
Date(int year = 1900,int month = 1,int day = 1)
:_year(year),
_month(month),
_day(day)
{}
//重载运算符 >> <<
friend ostream & operator<< ( ostream& out , const Date& d );
friend istream & operator>> ( istream& in , Date& d );
private:
int _year;
int _month;
int _day;
};
ostream & operator<<( ostream& out , const Date& d )
{
out<<"year:" <<d. _year<<endl ;
out<<"month:" <<d. _month<<endl ;
out<<"day:" <<d. _day<<endl <<endl;
return out ;
}
istream & operator>> ( istream& in , Date& d )
{
cin>>d._year;
cin>>d._month;
cin>>d._day;
return in;
}
int main()
{
Date d1;
cin>>d1;
cout<<d1;
return 0;
}
3、友元类
将一个类B定义为另一个类A的友元类,那么B就可以访问A中所有的成员
友元破坏了C++程序的封装性,尽量不适用友元,只在恰当的时候适用
四、静态成员
静态变量:存放在全局区
当该类需要一个所有成员对象所共享的变量时,这时候最好适用静态成员(static)
#include <iostream>
using namespace std;
class AA
{
public:
AA()
{
cout<<"AA()"<<endl;
++_count;
}
void show()
{
cout<<"count = "<<_count<<endl;
}
private:
int _a;
static int _count;
};
//静态成员变量需在类外初始化
int AA::_count = 0;
int main()
{
AA a1;
a1.show();
AA a2;
a2.show();
return 0;
}
注意:静态成员函数没有隐含this指针参数,所以可以使用类型::作用域访问符直接调用静态成员函数。
普通的成员函数必须需要成员变量来调用
但是静态成员函数还有另一种调动方法
因为静态成员函数没有this指针,不需要传参,所以也就不需要使用成员变量来调用了
那么,在静态成员函数中可以调用非静态成员函数嘛
答案是不行的,非静态成员函数有隐藏的this指针,在其内部可以访问成员变量,但是静态的成员函数GetCount根本没有this指针,也就无法传给show函数,所以也就无法调用show函数
同理,在静态成员函数中,也不可以访问普通成员变量,因为访问成员变量也需要this指针
那么,普通的成员函数可以访问静态的成员函数嘛?当然可以,静态成员函数属于整个类域,只要在类里面,就可以访问,在类外的话如果输public才可以访问