1. 初始化列表:
作用:提供初始化列表语法,用于初始化属性
语法:构造函数() : 属性1(值1),属性2(值2),属性3(值3)
2. 类对象作为类成员
C++类中的成员可以时另一个类的对象,该成员为对象成员。
注:当其他类对象作为本类成员,构造时先构造类对象,再构造自身,析构顺序与构造相反
C++编译器至少给一个类添加四个函数:
① 默认构造函数(无参,函数体为空)
② 默认析构函数(无参,函数体为空)
③ 默认拷贝函数,对属性进行值拷贝
④ 赋值运算符 operator= ,对属性进行值拷贝
3. 静态成员
静态成员是在成员变量和成员函数前加上关键字static ,称为静态成员
静态成员变量:
① 所有对象共享用一份数据
② 在编译阶段分配内存
③ 类内声明,类外初始化
静态成员函数:
① 所有对象共享一个函数
② 静态成员函数只能访问静态成员变量
class Test()
{
public:
//初始化列表初始化属性
Test(int a,int b,int c):m_a(a),m_b(b),m_c(c)
{
}
static void func()
{
//静态成员函数只能访问 静态变量
m_sA = 10086;
//m_c = 666; //无法访问
cout << "静态函数调用" << endl;
}
private:
int m_a;
int m_b;
int m_c;
//静态成员变量
static int m_sA;
}
//静态成员变量,类内声明,类外初始化
int Test::m_sA = 200;
class RunTest()
{
public:
RunTest(){
//1.通过对象访问
Test t;
t.func();
//2.通过类名访问
Test::func();
}
~RunTest(){}
private:
//注:当其他类对象作为本类成员,构造时先构造类对象,再构造自身,析构顺序与构造相反
Test m_test;
};
int main()
{
RunTest t();
system("puase");
return 0;
}
4. 对象模型和this指针
成员变量和成员函数分开储存,只有非静态成员变量才属于类的对象上
C++编译器会给每个空对象也分配一个字节空间,为了区分空对象占内存位置
this指针概念
C++通过提供特殊的对象指针,this指针,区分对象调用自己。this指针指被调用的成员函数所属的对象。
this指针是隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用即可。
作用:
① 当形参和成员变量同名时,可用this指针区分
② 在类的非静态成员函数中返回对象本身,可使用 return *this;
空指针访问成员函数
C++中空指针也是可以调用成员函数的,但要注意有无用到this指针
const 修饰成员函数
常函数:
成员函数后加const后,称这个函数为常函数
常函数类不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
声明对象前加const,称该对象为常对象
常对象只能调用常函数
class Person()
{
public:
Person(int num)
{
this.m_A = num;
}
//返回引用
Person& addNum(int num)
{
m_A += num;
return *this;
}
//返回新对象,调用拷贝函数
Person add(int num)
{
m_A += num;
return *this;
}
//指针本质时指针常量,指针指向是不可修改的
//const Person *const this;
//在成员函数后加const,修饰的是this指向
void show() const
{
//this->m_A = 100; //编译错误
//this = NULL //this指针不可修改指针的指向
this->m_C = 100;
}
int m_A; //非静态成员变量,属于类的对象上
void func(){} //非静态成员函数,不属于类的对象上
static int m_B; //静态成员变量,不属于类的对象上
static void func1(){} //静态成员函数,不属于类的对象上
mutable int m_C; //加关键字:mutable 常函数内仍可修改
};
int Person::m_B = 100;
int main()
{
//链式编程思想
Person p1(10);
Person p2(10);
p1.add(10).add(10).add(10); //返回引用,得出 40
p2.addNum(10).addNum(10).addNum(10); //返回值,得出 20
const Person p;
//p.m_A = 100; //编译报错
p.m_C = 100;
//常对象只能调用常函数
//p.add(10); //常函数 不可以调用普通成员函数,因为普通成员函数可以修改属性
p.show();
system("puase");
return 0;
}
5.友元
友元 目的是让函数或者类 访问另一个类中的私有成员。
关键字:friend
友元三种实现:
① 全局函数做友元
② 类做友元
③ 成员函数做友元
class FriendCl;
class Building
{
//goodGay全局函数 友元,可以访问 私有成员
friend void goodGay(const Building & building);
//FriendCl是友元类,可以访问 私有成员
//friend class FriendCl;
//visit是FriendCl类的友函数,可以访问 私有成员
friend void FriendCl::visit();
public:
Building();
public:
string m_sittingRoom; //客厅
private:
string m_bedRoom; //卧室
};
Building::Building()
{
m_sittingRoom = "客厅";
m_bedRoom= "卧室";
}
//① 全局函数 友元
void goodGay(const Building & building)
{
cout << "全局函数 访问公有成员:"<<building.m_sittingRoom << endl;
cout << "全局函数 访问私有成员:"<<building.m_bedRoom<< endl;
}
//② 类 友元
class FriendCl
{
public:
FriendCl();
void visit();
Building *m_building;
}
FriendCl::FriendCl()
{
m_building = new Building();
}
void FriendCl::visit()
{
cout << "友元类 访问公有成员:"<<building.m_sittingRoom << endl;
cout << "友元类 访问私有成员:"<<building.m_bedRoom<< endl;
}
int main()
{
//全局函数友元测试
Building build;
goodGay(build);
//友元类/友元函数 测试
FriendCl f;
f.visit();
system("pause");
return 0;
}
6.运算符重载
概念:对已有运算符重新进行定义,赋予其另外一种功能,以适应不同数据类型
对内置的数据类型的表达式的运算符是不可能改变的;不要乱用运算符重载
(+加法运算符重载,<< 左移运算符重载,++递增运算符重载,=赋值运算符重载,
<、>、==、!= 关系运算符重载,()函数调用运算符重载)
class NumClass()
{
friend ostream & opearator<<(ostream &cout ,NumClass &c)
public:
NumClass(){}
NumClass(const int num):m_num(num){}
NumClass(const int a,const int b):m_a(a),m_b(b){}
~NumClass()
{
if(m_age != NULL)
{
delete m_age;
m_age = NULL;
}
}
//成员函数重载 +号
NumClass opearator+(NumClass &c)
{
NumClass tmp;
tmp.m_a = this->m_a + c.m_a;
tmp.m_b = this->m_b + c.m_b;
return tmp;
}
//运算符重载 也可以发生函数重载
NumClass opearator+(int &num)
{
NumClass tmp;
tmp.m_a = this->m_a + num;
tmp.m_b = this->m_b + num;
return tmp;
}
/
//重载前置++ 运算符(返回引用,为了一直对同一数据做递增操作)
NumClass& operator++()
{
m_num++;
return *this;
}
//重载后置++ 运算符(返回值,int为占位参数,可以用于区分前置和后置)
NumClass operator++(int)
{
NumClass tmp = *this; //先记录结果
m_num++; //后递增操作
return tmp; //返回记录结果
}
/
//重载 赋值运算符
NumClass& operator=(NumClass &c)
{
//编译器是提供浅拷贝
//m_age = c.m_age;
//应先判断是否属性在堆区,如果友先释放,后深拷贝
if(m_age != NULL)
{
delete m_age;
m_age = NULL;
}
m_age = new int(*c.m_age);
return *this;
}
//重载 关系运算符
bool operator==(NumClass &c)
{
returm (m_a == c.m_a &&
m_b == c.m_a &&
m_num == c.m_num);
}
//重载 函数调用运算符 (仿函数)
void operator()(string text)
{
cout << text();
}
int m_a;
int m_b;
int m_num;
int *m_age;
};
//全局函数重载 +号
NumClass opearator+(NumClass &c1,NumClass &c2)
{
NumClass tmp;
tmp.m_a = c1->m_a + c2.m_a;
tmp.m_b = c1->m_b + c2.m_b;
return tmp;
}
//全局函数重载 << 左移运算符
ostream & opearator<<(ostream &cout ,NumClass &c)
{
cout << "m_a:" << c.m_a << " m_b:" << c.m_a;
return cout;
}
int main()
{
NumClass n1(10,20);
NumClass n2(20,40);
//成员函数重载 本质调用
//NumClass n3 = n1.opearator+(n2);
//全局函数重载 本质调用
//NumClass n3 = opearator+(n1,n2);
NumClass n3 = n1+n2;
cout << "n3:m_a:" << n3.m_a << endl; //得30
cout << "n3:m_b:" << n3.m_b << endl; //得60
//运算符重载 也可以发生函数重载
NumClass n4 = n1+30;
cout << "n4:m_a:" << n4.m_a << endl; //得40
cout << "n4:m_a:" << n4.m_a << endl; //得50
//重载输出运算符
cout << "n4:" << n4 << endl;
//操作递增运算符
NumClass n5(100);
cout << "n5:" << ++n4 << endl; //得101
cout << "n5:" << n4++ << endl; //得100
cout << "n5:" << n4 << endl; //得101
//函数调用运算符重载
NumClass myClass;
myClass("Hello word");
//匿名函数对象
NumClass()("test");
system("pause");
return 0;
}