类的封装
一、参数初始化列表:
1.带参构造
类名(int 参数1, int 参数2....) //用来赋值的
{
属性1 = 参数1;
属性2 = 参数2;
}
2.初始化列表(常用)
类名(<类型1> 参数1, <类型2> 参数2...): 属性1(参数1), 属性2(参数2)
{
}
注意:初始化列表与函数内部赋值的区别:
1.初始化列表顾名思义是进行初始化操作,是早于赋值的一个操作,而且初始化只能有一次.
2.有的成员属性只能在初始化列表中操作: const 修饰的变量 , 引用方式
二、组合思想
1.一个类包含一个或多个其他类的对象.
2.构造与析构顺序:先构造类中的对象,再构造自身. 析构顺序与构造相反.
例如:
class dog // 必须先定义出来
{
public:
};
class person //person这个类包含dog这个类时,必须先定义出dog这个类
{
public:
dog d1;
};
三、对象模型与this指针
1.对象的成员属性与成员方法其实是分开存储的,类中的所有成员方法都只有一份实例
2.只有非静态成员属性才会占用对象空间,可以使用sizeof运算符来验证.
注意:所有对象共享一份代码实例(执行指令),就是通过this指针来区分的
3.this指针是每一个非静态成员函数都拥有的参数,只是该参数被编译器隐藏,但是可以在函数内使用!!
this指针: 指向当前调用成员函数的对象.
class Person
{
int PersonFun(int n)
{
this->num = n;
}
int num;
};
this指针的作用:
1.区分成员属性与参数 (属性与参数重名)
2.成员函数需要返回对象本身时,需要使用this. (实现链式编程思想)
3.this本质是一个 指针常量: Person * const this 因此this在函数内部的指向是不能改变的!!
四、static关键字
1.static修饰成员变量
static修饰成员变量,被称为静态成员变量
特点:
1、静态成员变量的空间开辟以及释放 和 对象的空间开辟、释放没有关系. 而是在编译阶段开辟,程序结束释放
2、需要在类内声明,类外初始化.(初始化时,就在开辟空间)
3、所有对象共享一份数据.
注意: 逻辑上该静态成员变量还是属于类的 所以需要作用域符号来初始化 int Person::n = 12;
代码举例:
class person
{
public:
static int age;
};
int person::age = 23; //必须在类外初始化
静态成员变量,可以通过类名直接访问 Hero::n, (当然对象名肯定也可以)
非静态成员只能通过对象名来访问, Hero h1; ------>h1.n2
2.static修饰成员函数
static修饰成员函数,被称为静态成员函数
特点:
1、静态成员函数,是被所有对象共享的函数.
2、静态成员函数在编译阶段展开,所以内部的变量需要在编译阶段就存在.
所以静态成员函数内部只能访问静态成员变量,不能访问非静态成员变量.
因为静态成员变量在编译阶段已经存在了.
静态成员函数 与 普通成员函数主要的区别就是没有this指针,所以函数内部不区分对象.
所以静态成员函数可以直接使用类名来访问: Hero::static_fun()
五、const关键字
1.常成员函数
语法:
class A
{
void ReadA() const //常成员函数.
{
//不能出现修改成员属性操作.
}
};
注意:
1.常成员函数内部不允许修改成员属性
2.原理: this 原本是一个指针常量. obj * const this; 再函数之后加一个const. 则 this 会被修饰
3.变成: const obj * const this this的指向以及指向空间中的内容都不能被修改.
2.常对象
1.语法:在实例化对象时加const 修饰: const Hero h1;
2.常对象中的所有属性都不能再被修改,所以常对象只能调用常成员函数
六、运算符重载
1.给予运算符新的意义,使其能够支持自定义类型的操作.
2.运算符重载还可以再发生函数重载.
3.运算符分为: 单目运算符(一个操作数)、双目运算符(两个操作数)、三目运算符(三个操作
数).
注意:运算符重载后的操作数不能改变,不能重载内置数据类型(float、int等..)
语法:
<类型(返回值)> operator<运算符>(<参数1>...)
{
}
例如:
void operator+(int _n1)
{
}
1.成员运算符重载:在类中进行运算符重载
2.调用运算符的对象要算一个操作数.
3.全局运算符重载:在所有类外进行运算符重载
4.根据参数顺序来决定运算符的操作数,第一个参数作为运算符左操作数,第二个参数作为运
算符右操作数.
例如:
#include <iostream>
#include <ostream>
using namespace std;
class Person
{
public:
Person():p_name(""),p_age(0) //初始化
{
}
Person(string name, int age):p_name(name), p_age(age) //带参构造赋值
{
}
#if 0
void operator<<(Person &p) //类内中给与 << 运算符新的规则,要求它实现输出类里面的内容
{
cout << "姓名:" << p.p_name << endl;
cout << "年龄:" << p.p_age << endl;
}
#endif
string p_name;
int p_age;
};
ostream & operator<<(ostream &out, const Person &p) //类外中给与 << 新的定义,输出类内中的内容
{
out << "姓名:" << p.p_name << endl;
out << "年龄:" << p.p_age << endl;
return out;
}