赋值运算符重载函数
类名& operater=(const 类名& 形参){
// 赋值操作
return *this;
}
调用时机:
赋值代码
Bill Bill::operator=(const Bill& b){
price = b.price;
count = b.count;
discount = b.discount;
if(NULL != name){
delete [] name;
name = NULL;
}
拷贝构造函数与赋值操作符的区别
拷贝构造函数:当一个已经存在的对象来初始化一个未曾存在的对象。赋值操作符:当两个对象都已经存在。
深拷贝与浅拷贝
浅拷贝:只拷贝指针地址(引用)。深拷贝:重现分配堆内存,拷贝指针指向内容(构造)。
友元
作用:
非成员函数访问类中的私有成员分类
全局友元函数:将全局函数声明成友元函数友元成员函数:类的提前引用声明,将一个函数声明为多个类的友元函数
友元类:将整个类声明为友元
特点
友元关系单向性友元关系不可传递
代码
class Bill{
friend void sum(Bill);
friend void sum(Bill*);
//friend void Bills::PrintAll();
friend class Bills;
。。。。。
}
const限定符
本质:不可修改。
const 类型 变量 = 初始值;
const 类型 对象;
类型 const 变量 = 初始值;
类型 const 对象;
例:
const int size = 4;
int const size = 4;
定义时必须初始化全局作用域声明的const变量默认作用域是定义所在文件
const对象只能调用const成员函数
const与宏定义#define的区别
const 宏定义#define
编译器处理方式 编译运行阶段使用 预处理阶段展开/替换
类型 有具体的类型 没有类型
安全检查 编译阶段会执行类型检查 不做任何类型检查
存储方式 分配内存 不分配内存
const与指针
No. 类型 语法 作用
1 const指针 类型* const 变量 = 初始值; 指针指向地址不能改变
2 指向const对象的指针 const 类型* 变量 = 初始值; 指针指向对象不能改变
类型 const* 变量 = 初始值;
3 指向const对象的const指针 const 类型* const 变量 = 初始值; 指针指向地址和对象不能改变
const成员变量
1.不能在类声明中初始化const数据成员;2.const成员变量只能在类构造函数的初始化列表中初始化;
3.如果使用const成员变量不能使用赋值运算符重载函数(不能被修改)。
class 类名{
public:
类名(类型 形参):成员变量(形参){}
private:
const 类型 成员变量;
}
const位置与作用
const修饰位置 作用
变量 变量不可修改,通常用来替代#define
对象/实例 对象的成员变量不可修改,只能调用const成员函数
函数参数 参数不能在函数内部修改,只作为入参
函数返回值 返回的结果不能被修改,常用于字符串
成员变量 只能在初始化列表中初始化
成员函数 不改变成员变量
PS:只要能够使用const,尽量使用const。static限定符
本质:
生存周期:整个程序的生存周期。作用域:属于类,不属于对象。
声明
class 类名{
static 返回类型 函数(形参列表);
};
定义
返回类型 类名::函数(形参列表){
函数体;
}
调用
类名::函数(实参列表);
规则
static只能用于类的声明中,定义不能标示为static。非静态是可以访问静态的变量和函数
静态成员函数可以设置private,public,protected访问权限
禁忌
静态成员函数不能访问非静态函数或者变量静态成员函数不能使用this关键字
静态成员函数不能使用cv限定符(const与virtual)
PS:因为静态成员函数是属于类而不是某个对象。
静态成员变量
语法:
1.在类定义中声明,但是在类实现中初始化。2.在声明时需要指定关键字static,但是实现时不需要指定static。
3.对象的大小不包含静态成员变量
因为静态成员变量是属于类而不是某个对象。静态成员变量所有类的对象/实例共享。
static修饰位置与其作用
static修饰位置 作用
变量 静态变量
函数 只源文件内部使用的函数
成员变量 对象共享变量
成员函数 类提供的函数,或者作为静态成员对象的接口
const static限定符
变量类型 声明位置
一般成员变量 在构造函数初始化列表中初始化
const成员常量 必须在构造函数初始化列表中初始化
static成员变量 必须在类外初始化
static const/const static成员变量(必须是整形) 变量声明处或者类外初始化
代码例子
#include <iostream>
using std::cout;
using std::endl;
class StaticConstTest{
public:
void print(){
cout << test1 << " " << test2 << endl;
}
private:
static const int test1 = 1;
static const int test2;
};
/* static */ const int StaticConstTest::test2 = 2;
int main(){
StaticConstTest sct;
sct.print();
}
函数的调用优化——内联
本质
内联函数的代码直接替换函数调用,省去函数调用的开销。条件
一般用在代码比较简单的函数。语法
关键字inline必须与函数实现/定义体放在一起才能使函数成为内联,将inline放在函数声明前面不起任何作用。定义在类声明之中的成员函数将自动地成为内联函数。
慎用内联
如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
不要随便地将构造函数和析构函数的定义体放在类声明中。
代码
inline /*friend*/ bool operator==(const Rational& left,const Rational& right){
return &left == &right or left.numer*right.denom == left.denom*right.numer;
}
运算符重载
本质
函数重载成员函数运算符重载
返回值类型 operator 运算符(参数){
函数体
}
友元函数运算符重载
friend 返回值类型 operator 运算符(形参列表) {
函数体
}
规则
五个不能重载的运算符:成员运算符.、指针运算符*、作用域运算符::、sizeof、条件运算符?:不允许用户自定义新的运算符,只能对已有的运算符进行重载
重载运算符不允许改变运算符原操作数的个数
重载运算符不能改变运算符的优先级
重载运算符函数不能有默认的参数,会导致参数个数不匹配
代码
/*friend*/ ostream& operator<<(ostream& out,const Complex& c){
out << c.real << "+" << c.imag << "i" << endl;
return out;
}
Complex Complex::operator+(const Complex& other)const{
Complex res;
res.real = other.real + this->real;
res.imag = other.imag + this->imag;
return res;
}//用构造函数Rational(int n):numer(n),denom(1){}
inline /*friend*/ bool operator==(const Rational& left,const Rational& right){
return &left == &right or left.numer*right.denom == left.denom*right.numer;
}