目录
1、成员变量和成员函数分开存储
1.1空对象占用的内存空间
1.2只有非静态成员变量,属于类对象上,影响类对象所占的内存,会涉及到内存对齐
2.this指针
2.1解决名称冲突,
2.2返回对象本身用*this
3、空指针访问成员函数
4.const修饰成员函数--常函数
4.1常函数
4.2常对象
#include
using namespace std;//在类中,所有的函数也好,变量也好,我们都称为成员,
// 但这些数据是分开存的,虽然我们封装的概念,是把他们作为一个整体来展现生活中的事物
// 但是这些数据不是都放在一起//成员变量和成员函数分开存储
class Person
{};
void test01()
{Person p;//空对象占用的内存空间为:1个字节//C++编译器会给每个空对象也分配一个字节的空间,是为了区分空对象占内存的位置//每个空对象它也在内存上,当你创建两个空对象时,这两个空对象不能占同一块内存叭//每个对象都应该有独一无二的内存空间,因此我们给它分配一个字节去占用一个内存空间//不能让它俩在一个位置上cout << "size of p = " << sizeof(p) << endl;//输出:1cout << "size of p = " << sizeof(Person) << endl;//输出:1
}
int main()
{test01();system("pause");//按任意键继续return 0;
}
#include
using namespace std;//在类中,所有的函数也好,变量也好,我们都称为成员,
// 但这些数据是分开存的,虽然我们封装的概念,是把他们作为一个整体来展现生活中的事物
// 但是这些数据不是都放在一起//成员变量和成员函数分开存储
class Person
{int m_A;//非静态的成员变量 属于类对象上static int m_B;//静态成员变量 不属于类对象上,有没有它类对象所占的内存不会变void func() {};//非静态成员函数 不属于类对象上,有没有它类对象所占的内存不会变static void func2() {};//静态成员函数 不属于类对象上,有没有它类对象所占的内存不会变//不属于类的对象,大家都共享一份数据
};
int Person::m_B = 0;//静态成员变量,类内声明,类外初始化
void test02()
{Person p;cout << "size of p = " << sizeof(p) << endl;//输出4/** 内存对齐简单说一下,在32位操作系统下,我们普遍用的gcc编译器和vs编译器都是默认按照4个大小进行内存对齐的也就是说结构体或类中的内存分配默认是按照4个字节的倍数进行分配的。比如有两个成员, int a; char b; 如果按大小相加的话应该为5字节,但由于内存对齐是8个字节再举个例子理解的更全面一些,比如有两个成员 char a; char b;这时的类的大小就为两字节,因为这个时候成员都是char型的,都占一个字节的空间,本身就对齐了,不要内存对齐操作再举个例子,3个char型,一个int型,内存对齐后为8属于计算机组成原理的内容*/
}
int main()
{test02();system("pause");//按任意键继续return 0;
}
下面的代码会随机给一个年龄,并不是18岁
#include
using namespace std;//this指针的概念//2、返回对象本身用*thisclass Person
{
public:Person(int age){age = age;//把鼠标放到age上可以看到三个阴影//我们没有将属性age进行一个赋值操作}int age;};//1、解决名称冲突
void test01()
{Person p1(18);cout << "p1的年龄为:" << p1.age << endl;//输出为乱码
}
int main()
{test01();system("pause");//按任意键继续return 0;
}
解决方法一:起不一样的名字
#include
using namespace std;//this指针的概念//2、返回对象本身用*thisclass Person
{
public:Person(int age){m_Age = age;}int m_Age;};//1、解决名称冲突
void test01()
{Person p1(18);cout << "p1的年龄为:" << p1.m_Age << endl;
}
int main()
{test01();system("pause");//按任意键继续return 0;
}
解决方法二:this指针
#include
using namespace std;//this指针的概念//2、返回对象本身用*thisclass Person
{
public:Person(int age){//this指针指向 被调用的成员函数 所属的对象//现在是p1调用,就指向p1this->age = age;}int age;};//1、解决名称冲突
void test01()
{Person p1(18);cout << "p1的年龄为:" << p1.age << endl;
}
int main()
{test01();system("pause");//按任意键继续return 0;
}
#include
using namespace std;//this指针的概念class Person
{
public:Person(int age){//this指针指向 被调用的成员函数 所属的对象//现在是p1调用,就指向p1this->age = age;}void PersonAddAge(Person &p){this->age += p.age;//自身的年龄加上穿进来的人的年龄}int age;};//2、返回对象本身用*this
void test02()
{Person p1(10);Person p2(10);p2.PersonAddAge(p1);//p2.PersonAddAge(p1).PersonAddAge(p1);//因为p2.PersonAddAge(p1)的返回值为void,//所以不能在调用PersonAddAgecout << "p2的年龄为:" << p2.age << endl;
}
int main()
{test02();system("pause");//按任意键继续return 0;
}
如果返回的是p2那我就可以接着调用
#include
using namespace std;//this指针的概念class Person
{
public:Person(int age){//this指针指向 被调用的成员函数 所属的对象//现在是p1调用,就指向p1this->age = age;}Person& PersonAddAge(Person &p){this->age += p.age;//当p2调用这个函数的时候,this就指向p2//this是指向p2的指针,而*this指向的就是p2这个对象的本体return *this;//返回这个对象的引用是为了保证是同一个p2//在拷贝构造函数那里讲过,以值的方式返回,不会返回p2//,会调用拷贝构造函数,拷贝出来一个新的返回,返回p2的副本//如下图所示}int age;};//2、返回对象本身用*this
void test02()
{Person p1(10);Person p2(10);//链式编程思想,后面可以无限追加p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);cout << "p2的年龄为:" << p2.age << endl;
}
int main()
{test02();system("pause");//按任意键继续return 0;
}
空指针是可以访问成员函数的,没有加this的可以直接调用,加this的也可以写个判断
#include
using namespace std;//空指针调用成员函数
class Person
{
public:void showClassName(){cout << "this is Person class" << endl;}void showPersonAge(){//在属性前面都默认加了个this,this->m_Age,表示当前对象的一个属性//报错原因,是因为传入的指针为空,this也是空的,没有确定的对象,空的值//还要访问属性,不可能的cout << "age = " << m_Age << endl;/*//所以一般可以这样写,提高代码健壮性,如果传的是空指针我也不空if (this == NULL){return;}cout << "age = " << m_Age << endl;*/}int m_Age;
};
void test01()
{Person* p = NULL;//创建一个空指针,访问两个函数p->showClassName();p->showPersonAge();//修改前会报错
}
int main()
{test01();system("pause");//按任意键继续return 0;
}
#include
using namespace std;//常函数
class Person
{
public://在成员函数后加const,修饰的是this指针,让指针指向的值也不可以修改void showPerson() const{//m_A = 100;报错//每个成员函数内部都有一个this指针//等价于this->m_A=100,在属性前都默认加了个this//this指针的本质 是指针常量,指向不可以更改,内容可以更改//this = NULL;//this已经指向了p,指向不可以修改//相当于Person * const this;this指向的是Person,是一个Person*的指针//在成员函数后面加const,相当于const Person * const this,本质上是修饰的this指针// 让this指向的内容也不可以修改,//不可以修改指向值的指针m_B = 100;}int m_A;mutable int m_B;//特殊变量,即使在常函数中,也可以修改这个值,需要加关键字mutable
};void test01()
{Person p;p.showPerson();
}
int main()
{system("pause");//按任意键继续return 0;
}
常对象的属性也是不允许修改的
#include
using namespace std;//常函数
class Person
{
public:void showPerson()const{m_B = 10;}void func(){m_A = 100;}int m_A;mutable int m_B;//特殊变量,即使在常函数中,也可以修改这个值,需要加关键字mutable
};void test02()
{const Person p;//在对象前加const,变为常对象//p.m_A = 100;常对象的属性也是不允许修改的p.m_B = 1000;特殊变量,在常对象中,也可以修改这个值//常对象只能调用常函数//常对象不能调用普通的成员函数,因为普通成员函数可以修改属性p.showPerson();//p.func();//报错,如果这个函数能调用,那么我们就把属性给改了,//而我们说,常对象的属性也是不允许修改的}
int main()
{system("pause");//按任意键继续return 0;
}