类的介绍
类的三大特性:封装 继承 多态
类是在结构体的基础上进化而来
类由成员变量(属于对象),成员方法(属于类)构成
创建对象时开辟的空间是用来存储成员变量的
成员方法是属于类的,不属于对象。所有对象调用的方法,都是同一类方法
类与结构体
类和c结构体唯一的区别就在于结构体的默认权限为公共 ,类的默认权限为私有
封装
封装的意义:
1.将属性和行为作为一个整体,就像生活中的事物
语法:class 类名{ 访问权限:属性 / 行为 };
如下一个简单的程序实现进行演示说明:
class PlayerBase
{
public: 访问权限
int m_nID; 微软写法,在每个属性命名开头加一个m_
char m_pszName;
int m_nHP;
int m_nMP;
double m_dbPosX;
double m_dbPosY; 以上都是属性
public: 访问权限
void text()
{
std::cout << "text" << std::endl 这是一个类方法,即行为
}
}
int main()
{
PlayBase Playerobject; 创建一个类对象
Playerobject.m_nID = 1; 由于是public访问属性,所以可以定义该属性
std::cout << Playerobject.m_nID << ste::endl; 同样因为是公共属性,所以也可以访问
}
2.将属性和行为加以权限控制
类具有访问权限:私有 公共 保护
在类中,所有成员默认私有(private),类中成员自己可以使用,类外不可用,也不可继承
公共的(public):大家都可以使用,也可以继承
保护的(protected):私有成员变量或函数在类的外部是不可访问的,只有本类和友元函数
可以问访问保护成员,并且子类也可以访问
私有的(private):私有成员变量或函数在类的外部是不可访问的,只有本类和友元函数可以访问
私有成员,默认情况下,类的所有成员都是私有的。
私有属性访问
在一般类中,最为常见的类形式是只有ID处于公共属性内,其余在私有属性中,保障类私密性
假设我们将上述类中属性m_nHp设置为一个私有的访问属性,以此为例述一个外界能够访问私有属性和方法的方法:
类中定义public方法
int SetHP(int nHP) 外界赋值私有变量
{
m_nHp = nHP;
}
int GetHP() 返回私有变量
{
return m_nHP;
}
Playerobject.SetHP(12138); 定义私有变量m_nHp
Playerobject.GetHP() 返回该私有变量的值
静态成员
将关键字static用于类的某成员,这样该成员就成为静态成员,静态成员也具备访问权限
静态成员包括静态数据成员和静态成员函数
静态变量
静态数据成员:
1.所有类对象共享同一份数据
2.在编译阶段分配内
存
3.类内声明,类外初始化
4.可通过对象以及类名进行访问
如下一个类进行演示讲解
class PlayerBase
{
public:
static int m_objectobject; 定义一个静态成员变量
public:
PlayerBase()创建构造函数
{
m_objectobject++;
}
}
创建四个对象
PlayerBase obj1; 此时m_objectobject+1
PlayerBase obj2; 此时m_objectobject+1
PlayerBase obj3; 此时m_objectobject+1
PlayerBase obj4; 此时m_objectobject+1
访问静态变量方式一:通过对象访问
std::cout<<obj4.m_objectobject<<std::endl;
std::cout<<obj3.m_objectobject<<std::endl; 也可通过其他对象打印
访问静态变量方式二:通过类名访问
std::cout<<PlayerBase::m_objectobject<<std::endl;
打印输出都是4
由上程序可验证m_objectobject为静态数据成员,它为各对象所共有,不管创建多少对象,静态变
量只会初始化一次
即使有多个PlayerBase 对象,m_objectobject在内存中也只占一份空间,而不是每个对象都分配
m_objectobject空间
m_objectobject的值对所有对象都是一样的,若改变m_objectobject的值,则各对象h的值都同时改
变了。
静态方法
静态成员函数:
1.所有对象共享同一个函数
2.静态成员函数只能访问静态成员变量
3..静态成员存在于内存,无需生成对象就可被调用
4..静态函数不能直接调用非静态的成员变量
5.不能使用this引用
如下一个程序进行讲解:
class Person
{
public:
static int m_A; 定义一个静态成员变量
int m_B; 定义一个普通变量
static void func()
{
std::cout << "func调用" << std::endl;
m_A = 100;
m_B = 100; 错误,不可以访问非静态成员变量
}
};
静态成员变量方法有两种访问方式:
1.通过对象
Person p1;
p1.func();
2.通过类名
Person::func(); 如果该静态成员方法是私有的,则无法访问
匿名对象
匿名对象,不加对象名的类对象。创建对象时调用构造函数后,找不到先前创建的对象(没有对象名称)。周期只有一行,进入下一行时,该对象立刻销毁,调用析构函数 。
匿名对象的作用:能够更为直接地应用一次类中的方法,如:
Playerase().func() 先Playerase()创建匿名对象后Playerase().func()调用类方法
this指针
在C++中,类内的成员变量和成员函数分开存储。只有非静态成员变量才属于类的对象上,占有对
象空间,静态成员变量不占对象空间,所有类型函数也不占对象空间,共享一个函数实例
由于多个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一个函数
实例,此时可以利用this指针取区分每个对象调用自己的函数
在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,叫做this指针。
this指针是隐含每一个非静态成员函数内的一种指向被调用的成员函数所属的对象首地址的指针,
其本质是一个指针常量,指针的指向不可修改,但其指向的对象的数据可以修改。this指针不需要
定义,可以直接使用。如果想让正常的指针指向的值也不可以修改,需要声明常函数
this指针的用途:
1.当形参和成员变量同名时,可用this指针来区分
如:this->m_pszName = m_pszName;
2.在类的非静态成员函数中返回对象本身,可使用return *this
如:
class Person
{
public:
int age;
Person& PersonAddPerson(Person p)
{
this->age += p.age;
return *this; 返回对象本身
}
const修饰成员变量
常函数:
1.成员函数后加const后我们称为这个函数为常函数
2.常函数内不可以修改成员属性
3.成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
1.声明对象前加const称该对象为常对象
2.常对象只能调用常函数
如下一个程序进行演示与讲解
class Person
{
public:
int m_A;
mutable int m_B; const函数中该变量可被修改
public:
Person()
{
m_A = 0;
m_B = 0;
}
void ShowPerson() const
{
this->m_A = 100 错误,const修饰成员函数,表示指针指向的内存空间的数据不能修改
this->m_B = 100; m_B被mutable修饰的变量了,所以它的值可以被修改
}
};
void test01()
{
const Person person; 常量对象
person.m_A = 100; 错误,常对象不能修改成员变量的值
std::cout << person.m_A << std::endl; 但是可以访问
person.m_B = 100; 但是常对象可以修改mutable修饰成员变量
person.MyFunc(); 错误,常对象不能调用const修饰的函数
}
深浅拷贝
浅拷贝
同一类型的对象之间可以赋值(没有指针的情况下),使得两个对象的成员变量的值相同,两个对
象仍然是独立的两个对象,这种情况被称为浅拷贝.
简单的说,浅拷贝就是简单的赋值拷贝操作
深拷贝
当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函
数,自行给指针动态分配空间,这就是深拷贝。
简单的说,深拷贝就是自定义一个拷贝构造函数
如下一个程序进行演示讲解:
class Person
{
public:
Person() 无参(默认)构造函数
{
std::cout << "无参构造函数!" << std::endl;
}
Person(int age ,int height) 有参构造函数
{
std::cout << "有参构造函数!" << std::endl;
m_age = age;
m_height = new int(height);
}
Person(const Person& p) 拷贝构造函数 const修饰,传入参数不可被改变,如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
{
std::cout << "拷贝构造函数!" << std::endl;
m_age = p.m_age;
m_height = new int(*p.m_height);
}
~Person() 析构函数
{
std::cout << "析构函数!" << std::endl;
if (m_height != NULL)
{
delete m_height;
}
}
public:
int m_age;
int* m_height;
};
void test01()
{
Person p1(18, 180); 创建对象初始化
Person p2(p1); 拷贝构造
}
总结:深拷贝和浅拷贝的区别是在对象状态中包含其它对象的引用的时候,深拷贝的实现需要构造
拷贝函数新建一个堆区空间在进行拷贝,浅拷贝直接拷贝即可(简单的值的拷贝)。