1.默认成员函数:
初始化和清理:构造函数主要完成初始化工作
析构主要完成清理工作
6个默认成员函数 拷贝复制 :拷贝构造是使用同类对象初始化创建对象
赋值重载主要是把一个对象赋值给另一个对象
编译器生成的默认构造和opearator=引出浅拷贝问 题
取地址重载:主要是普通对象,const对象取地址,这两者很少
2.const成员变量:
1.对象调用const成员函数:const 只能传给const
class Date
{
public:
Date(int year, int mouth, int day)
{
_year = year;
_mouth = mouth;
_day = day;
}
//void Print()=>void Print(Date*this)
void Print()const//=>void Print (const Date*this)
{
cout << _year << "-" << _mouth << "-" << _day << endl;
//不能修改成员变量了,因为const修饰保护了*this
//_year=10;
}
//p1和p2没区别,一般情况下喜欢p1的写法
//const Date*p1;->*p1 指向的对象
//Date const*p2;->*p2 指向的对象
//Date*const p3;->p3 指针本身
private:
int _year;
int _mouth;
int _day;
};
void f(const Date& d)
{
d.Print();//const只能传给const
}
int main()
{
Date d1(2020, 4, 9);
f(d1);
d1.Print();//权限缩小
return 0;
}
1.const对象不可以调用非const成员函数
2.非const对象可以调用const成员函数
3.const成员函数内不可以调用其他非const成员函数
4.非const成员函数内可以调用其它的const函数
2.成员函数调用const成员函数:
class Date
{
public:
Date(int year=0, int mouth=1, int day=1)
{
_year = year;
_mouth = mouth;
_day = day;
}
//void Print()=>void Print(Date*this)
void Print()const//=>void Print (const Date*this)
{
cout << _year << "-" << _mouth << "-" << _day << endl;
}
void f1()//void f1(Date*this)
{
f2();//this->f2(this);//可以,属于权限缩小
}
void f2()const//void f2(const Date*this)
{
}
/*void f3()//void f3(Date*this)
{
}
void f4()const//void f4(const Date*this)
{
f3();//this->f(this);//不行,属于权限放大
}*/
private:
int _year;
int _mouth;
int _day;
};
int main()
{
Date d1(2020, 4, 9);
return 0;
}
3.成员函数调用const成员函数:
class Date
{
public:
Date(int year = 0, int mouth = 1, int day = 1)
{
_year = year;
_mouth = mouth;
_day = day;
}
//void Print()=>void Print(Date*this)
void Print()const//=>void Print (const Date*this)
{
cout << _year << "-" << _mouth << "-" << _day << endl;
}
Date* operator&()
{
cout << "operator&()" << endl;
return this;
}
const Date* operator&()const//const Date*
{
cout << "operator&()const" << endl;
return this;//const Date*
}
private:
int _year;
int _mouth;
int _day;
};
//取地址符重载
int main()
{
Date d1;
Date d2;
const Date d3;
cout << &d1 << endl;
cout << &d2 << endl;
cout << &d3 << endl;
return 0;
}
4.外部函数调用operator:
#include"Date.h"
void Fun(const Date& d3, const Date& d4)
{
cout << d3 - d4 << endl;//d3.operator-(&d3,d4)//&d3的类型是const Date*
}
int main()
{
Date d1(2019, 4, 18);
Date d2(2020, 4, 18);
cout << d1 - d2 << endl;//d1.operator-(&d1,d2)
Fun(d1, d2);
return 0;
}
3.再识构造函数:(另一种构造函数,增加了初始化列表)
1.初始化列表式的构造函数:
//再识构造函数
class Date
{
public:
Date(int year=0, int mouth=1, int day=1)
{
//函数体内赋值
_year = year;
_mouth = mouth;
_day = day;
}
//初始化列表式构造函数
Date(int year = 0, int mouth = 1, int day = 1)
:_year(year)
, _mouth(mouth)
, _day(day)
{ //初始化列表
}
private:
int _year;
int _mouth;
int _day;
};
2.为什么会有初始化列表这个东西?
必须用初始化列表形式构造函数的原因:
1.const成员变量
2.引用成员变量
3.没有默认构造函数的自定义成员变量
class A
{
public:
A(int a=0)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
//可以理解成初始化列表是对象的成员变量的定义的地方
B(int b, int ref)
:_aobj(b)
,_ref(ref)
, _n(5)
{
_x = 10;
}
private:
A _aobj;//没有默认构造函数(不要传参就可以调用的那个函数)
int& _ref;//引用
const int _n;//const
//成员变量的声明
int _x;
};
class Time
{
public:
Time (int hour = 0)
:_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
/*Date(int day)
{
Time t(1);
_t = t;
}*/
Date(int day)
:_t(1)
{
}
private:
int _day;
Time _t;
};
3.成员变量在类中声明的次序就是其在初始化列表中初始化顺序,与其在初始化列表中的先后顺序无关
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print()
{
cout << _a1 << _a2 << endl;
}
private:
int _a2;
int _a1;
};
int main()
{
A aa(1);
aa.Print();//1,随机值
return 0;
}
4.隐式类型转换:关键字explicit可以防止出现隐式类型的转换
class Date
{
public:
//explicit Date(int year = 0) explicit可以防止出现隐士类型的转换
Date(int year = 0)
:_year(year)
{
}
private:
int _year;
int _mouth;
int _day;
};
//C++11
class Date
{
public:
Date(int year,int mouth,int day)
:_year(year)
,_mouth(mouth)
,_day(day)
{
}
private:
int _year;
int _mouth;
int _day;
};
int main()
{
Date d(1);
Date d1(1);//构造
Date d1(1, 2, 3);
//C++11
Date d2 = { 1,2,3 };//隐士类型的转换,C++11才支持这种构造
Date d2 = 2;//隐士类型的转换 构造出tmp(2),在用tmp拷贝构造d2(tmp)+优化成直接构造
const Date& d2 = 2;//引用就是中间初始产生的临时对象
Date d3 = d1;//拷贝构造
return 0;
}
4.static成员:
设计一个类,可以计算这个类总计产生了多少对象
1.第一种设计容易被篡改
int n = 0;
class A
{
public:
A()
{
++n;
}
A(const A& a)
{
++n;
}
};
A f1(A& a)
{
return a;//会创建一个临时变量A tmp=a;拷贝构造
}
A f2(A& a)
{
return a;//会创建一个临时变量A tmp = a; 拷贝构造
}
int main()
{
A a1;
A a2;
f1(a1);
f2(a2);
int n=1;//n被篡改了
cout<<n<<endl;
return 0;
}
2.第二种设计可以防止n被篡改:类私有成员变量里面声明n,类外面通过访问符定义n;
class A
{
public:
A()
{
++n;
}
A(const A& a)
{
++n;
}
static int Get()//没有this指针,函数中不能访问非静态的成员
{
return n;
}
private:
static int n;//声明 不属于某个对象,而是属于类的所以对象,属于这个类
//n不在对象中,n在静态区
};
int A::n = 0;//定义
A f1(A& a)
{
return a;
}
A f2(A& a)
{
return a;
}
int main()
{
A a1;
A a2;
f1(a1);
f2(a2);
cout << a1.Get() << endl;
cout << A::Get() << endl;
return 0;
}