const 修饰成员函数
在成员函数后面加const ,const 修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会被改变。
class Date
{
public:
Date()
{}
void show()
{
cout << "show()" << endl;
cout << _year << "-" << _month << "-" << _day << endl;
}
void show() const//const修饰this指针相当于void show(const Date* this)
{
cout<<"show() const"<<endl;
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d;
d.show();
const Date d1;
d1.show();
}
执行结果为:
const权限只可以缩小。
那么思考以下几种场景
1 . const 对象可以调用非const 成员函数和const 成员函数吗?//可以
2 . 非const 对象可以调用非const 成员函数和const 成员函数吗?//不可
3 . const 成员函数内可以调用其它的const 成员函数非const 成员函数吗?//可以
4 . 非const 成员函数内可以调用其它的const 成员函数非const 成员函数吗?//不可
在同一类中。在一成员函数中可以调用任一成员函数。
inline(内联)函数
以inline修饰的函数叫做内联函数,编译时C++编译器会调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
注意:
- inline函数以空间换时间,省区调用函数的开销,代码很长或者有循环/递归的的函数不适宜使用内联。
- inline对于编译器而言只是一个建议。编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
- inline必须函数定义放在一起,才能成为内联函数,仅将其放在声明前不起作用。
- 定义在类内的成员函数默认为内联函数。
class Date
{
public:
void func()//定义在类内默认为内联函数
{}
void show();//声明
private:
int _year;
int _month;
int _day;
};
inline void Date::show()//成员函数定义为内联
{
cout << _year << "-" << _month << "-" << _day << endl;
}
inline void TestDate();//全局函数定义为内联
【面试题】
尽量用enum ,const ,inline 替换#define
为啥呢?
宏的缺点:
- 不可调试(在预编译阶段,进行宏替换)
- 可读性差,易误用
- 无类型安全检查
宏的优点:
- 提高代码的复用性
- 提高性能
友元函数(friend)
友元函数允许在类外访问该类中的任何成员,就像成员函数一样
注意:
- 友元函数不是类的成员函数。
- 友元函数可通过对象访问类的所有成员,私有和保护成员也可以访问。
- 友元函数最大限度的破坏了类的封装性。
- 整个类可以是另一个类的友元。友元类的每个成员函数都是另一个类的友元函数都可访问另一个类中的保护或私有数据成员。
- 若B是A的友元函数,则B可以访问A,A不能访问B.
//友元类
class Date
{
public:
friend void show(const Date& d);
Date(int year, int month, int day )
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void show(const Date& d)
{
cout << d._year<< "-" << d._month << "-" << d._day << endl;
}
void TestDate()
{
Date d(2018,3,28);
show(d);
}
operator不是成员函数可定义为成员函数
输入输出运算符的重载的友元函数
class Date
{
public:
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream&in, Date& d);
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
istream& operator>>(istream& in, Date& d)//不能为const
{
in >>d._year;
in >> d._month ;
in >> d._day;
return in;
}
void TestDate()
{
Date d(2018,2,28);
cout << d;//输出
cin >> d;//输入
}
//友元类
class Time
{
public:
friend class Date;
Time(int hour, int minute, int second)
:_hour(hour)
, _minute(minute)
, _second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int year, int month, int day, const Time& t)
:_year(year)
, _month(month)
, _day(day)
, _t(t)
{}
void show()
{
cout << _year << "-" << _month << "-" << _day << endl;
cout << _t._hour << ":" <<_t. _minute << ":" << _t._second << endl;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
void TestDate()
{
Time t(19,34,29);
Date d(2018,3,29,t);
d.show();
}
类的静态成员
- static修饰
- 类的静态成员为该类型的所有对象对象所共享
class Date
{
public:
Date()
{
cout << "Date()" << endl;
++scount;
}
void show()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
static void Printcount()
{
cout << "Date count:"<<scount << endl;
}
private:
int _year;
int _month;
int _day;
private:
static int scount;//静态成员变量,count创建时间个数
};
int Date::scount = 0;
void TestDate()
{
Date d,d1;
//d.Printcount();
//访问静态成员
Date::Printcount();//结果为2
}
注意:
- 静态成员函数没有this指针,可用类型::作用域访问符直接调用静态成员函数
- 同样,类的非静态成员函数可访问静态成员。
构造函数拷贝赋值函数的N 种调用情况
class Date
{
public:
Date()//构造函数
{
cout << "Date()" << endl;
}
Date(const Date& d)//拷贝构造
{
cout << "Date(const Date& d)" << endl;
}
Date& operator =(const Date& d)//赋值运算符重载
{
cout << "Date& operator=(const Date& d)" << endl;
return *this;
}
~Date()//析构函数
{
cout << "~Date()" << endl;
}
};
// 1.Date 对象做参数传值 & 传引用
void fun1(Date d) //void fun1(Date& d)
// 2.Date 对象做返回值传值 & 传引用
Date fun2() // Date& fun2()
{
Date d;
return d;
}
// 3.Date 对象做临时返回值传值 &传引用(编译器优化问题)
Date& fun3() // Date& fun3()
{
return Date();
}
int main()
{
// 场景1
//Date d1;
//fun1(d1);
// 场景2
//Date d2 = fun2();
//// 场景3
Date d3;
d3 = fun3();
system("pause");
return 0;
}
解答:
场景1:传值时:调用Date(),拷贝,析构,传址时 只调用Date()
场景2:传值时:调用Date(),拷贝,析构,传址时,拷贝与析构顺序颠倒
场景3:传值时:两次拷贝构造,一次赋值运算符重载,一次析构,
传址时:Date(),Date(),~Date(),Date& operator=(const Date& d)
注意:
- 临时对象可优化
- 匿名对象Date(),可被优化
- 已存在的对象不能合并
试回答下列问题(小心会特别绕哦!):
class AA
{
public:
AA()//构造函数
{
cout << "AA()" << endl;
}
AA(const AA& d)//拷贝构造
{
cout << "AA(const AA& d)" << endl;
}
AA& operator =(const AA& d)//赋值运算符重载
{
cout << "AA& operator=(const AA& d)" << endl;
return *this;
}
//~AA()//析构函数
//{
// cout << "~AA()" << endl;
//}
};
AA f(AA a)
{
return a;
}
AA f1()
{
return AA();//匿名对象
}
void Test5()
{
f(AA());
}
void Test4()
{
AA aa = f1();
}
void Test1()
{
AA a1;
a1 = f(a1);
}
void Test2()
{
AA a1;
AA a2 = f(a1);
}
void Test3()
{
AA a1;
AA a2 = f(f(a1));
}
//Test1中调用了_2__次AA的拷贝构造函数, _1__次AA的赋值运算符函数的重载。
//Test2中调用了__2_次AA的拷贝构造函数, _0__次AA的赋值运算符函数的重载。
//Test3中调用了_3__次AA的拷贝构造函数, _0__次AA的赋值运算符函数的重载。
//Test4中调用了_0__次AA的拷贝构造函数, _0__次AA的赋值运算符函数的重载。
仅调用了构造函数
//Test5调用了_1__次AA的拷贝构造函数, _0__次AA的赋值运算符函数的重载。