基础知识请参照 >类&对象<
【const成员函数】
const成员函数,const修饰的是this指针指向的对象,保证调用这个const成员函数的对象在函数内不被修改。
class Date{
public:
void show()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void show() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
const Date d;
d.show();
system("pause");
return 0;
}
- const对象只能调用const成员函数
- 非const对象既能调用非const成员函数也能调用const成员函数
- const成员函数只能调用其他const成员函数
- 非const成员函数既能调用其他非const成员函数也能调用const成员函数
结论:
1.如果成员函数中需要修改成员变量,则不能加const
2.若只读,则最好加const,因普通对象和const对象都可调该函数
- 取地址运算符重载
Date* operator&()
{
return this;
}
const Date* operator&() const
{
return this;
}
一般来说,取地址操作符由系统给出,不用重载。但当你不想让取地址符取到地址时,就需要重载。这样的方式有两种:
1.返回空
2.只声明,不定义
此时编译能过,但链接失败。
【内联】
定义:
- 用inline修饰的函数,叫内联函数。编译时C++编译器会将内联函数展开,没有函数的压栈开销,提升程序运行速率。
可以看出,内联类似于宏。宏的优缺点:
优点:
1.宏常量——增强可维护性
2.宏函数——增强效率(预处理时宏替换,没有压栈)缺点
1.不方便调试
2.没有类型安全检查
3.宏可读性比较差,可维护性比较差(宏函数),容易出错
宏函数书写方式:
由于宏函数有时候可读性比较差,容易出错,由此C++提出内联函数。
inline int Add(int a, int b)
{
return a + b;
}
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
内联函数在Debug中,也会调用函数,形成栈帧,而在Release中会被优化,直接展开
内联特点:
- inline是一种空间换时间做法,省去压栈开销。但代码很长或有递归,循环时不宜用内联。
- 编译器会自动优化inline,若函数体内有递归等,编译器优化会忽略内联
- inline必须和函数定义放在一起,仅放声明中不起作用,无法形成内联函数
- 定义在类内的成员函数默认定义为内联函数
尽量用const,enum,inline替换 #define
【友元】
友元函数:
- 友元函数不是类的成员函数,只是用关键字在类中说明。
- 友元函数可以通过对象访问所有成员,包括私有和保护。
class Date
{
friend void show(const Date& d); //友元函数
public:
Date(int year = 2018, int month = 3, int day = 30)
:_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;
}
int main()
{
Date d;
show(d);
system("pause");
return 0;
}
友元类:
- 整个类是另一个类的友元
- 友元类的每个成员函数都是另一个类的友元函数,可以访问另一个类中所有成员,包括私有和保护
class Date
{
friend void show(const Date& d); //友元函数
friend class AA; //友元类
public:
Date(int year = 2018, int month = 3, int day = 30)
:_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;
}
class AA
{
public:
void show(const Date& d) //AA类想访问Date类的私有成员,需定义友元类
{
cout << d._year << "-" << d._month << "-" << d._day << endl;
}
void Modift(Date& d)
{
d._year = 1900;
}
};
int main()
{
Date d;
show(d);
AA aa;
aa.show(d);
aa.Modift(d);
show(d);
system("pause");
return 0;
}
注意:友元在一定程度上破坏了C++的封装性,所以应在适当的地方使用友元。
(低耦合高维护性,高耦合低维护性)
输入输出运算符重载(友元函数应用):
系统给出的输入输出运算符支持内置类型,不支持自定义类型,如:
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
Date(int year = 2018, int month = 3, int day = 30)
:_year(year)
, _month(month)
, _day(day)
{
}
void show()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
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)
{
in >> d._year;
in >> d._month;
in >> d._day;
return in;
}
int main()
{
Date d;
cin >> d;
cout << d << endl;
system("pause");
return 0;
}
【静态成员】
class Date
{
public:
Date(int year = 2018, int month = 3, int day = 30)
:_year(year)
, _month(month)
, _day(day)
{
++_count;
}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._day)
{
++_count;
}
void show()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//静态成员函数没有this指针
static int GetCount()
{
return _count;
}
private:
int _year;
int _month;
int _day;
static size_t _count; //只是声明一个静态变量
};
size_t Date::_count = 0; //定义静态变量
int main()
{
Date d;
cout << d.GetCount() << endl;
cout << Date::GetCount() << endl;
system("pause");
return 0;
}
结论:
- 静态成员函数无this指针,不能调用普通成员。
- 普通成员通过对象访问(this指针),可以调用静态成员函数。
- 成员函数——代码段,静态成员函数——数据段(静态区)
【N种构造拷贝构造的优化情况】
class Date
{
public:
Date()
{
cout << "Date()" << endl;
}
Date(const Date& d)
{
cout << "Date(const Date& d)" << endl;
}
~Date()
{
cout << "~Date()" << endl;
}
private:
int _year;
int _month;
int _day;
};
void fun1(Date d)
{}
Date fun2()
{
Date ret;
return ret;
}
Date fun3()
{
return Date();
}
int main()
{
Date d1;
fun1(d1);
cout << endl;
Date(); //也是定义一个对象,是一个临时对象(匿名对象),生命周期只在当前一行
cout << endl;
fun1(Date()); //先创建一个匿名对象,再拷贝构造,编译器会优化将其合二为一,只有一个构造
cout << endl;
Date d2 = fun2(); //若编译器不优化,则有一个构造,两个拷贝构造。编译器会将return的临时对象的拷贝构造和这里的拷贝构造合二为一
cout << endl;
Date d3 = fun3(); //编译器会进行两次优化,先生成一个构造,再对return的临时对象拷贝构造,最后返回来拷贝构造。三个合为一个构造
cout << endl;
system("pause");
return 0;
}
经典面试题:
class AA
{};
AA f (AA a)
{
return a ;
}
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的赋值运算符函数的重载。