在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。
#includeusing namespace std; class person { int m_a; //非静态成员变量 属于类的对象上的 static int m_b;//静态成员变量 不属于类的对象上的 void func() {} //非静态成员变量 不属于类的对象上的 static void func2() {} }; int person::m_b = 10; void test01() { person p; //空对象占用的内存空间为:??? 1个字节 //c++ 编译器会给每个空对象也分配一个字节空间,为了区分对象占内存的位置 //每个空对象也应该有一个独一无二的内存 cout << "size of p=="< 3.2 this指针概念 我们知道在C++中成员变量和成员函数是分开存储的
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码那么问题是:这—块代码是如何区分那个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的—种指针
this指针不需要定义,直接使用即可
this指针的用途:·当形参和成员变量同名时,可用this指针来区分 ·在类的非静态成员函数中返回对象本身,可使用return *this#includeusing namespace std; //1 解决名称冲突 //2 返回对象本身用 return *this class person { public: person(int age) { //this 指针指向的是 被调用的成员函数 所属于的对象 this->age = age; } person &personaddage(person& p) { this->age += age; //this 指向p2的指针, *this 指向的就是p2的对象的本体 return *this; } int age; }; //1 解决名称冲突 void test01() { person p1(18); cout << "p1的年龄" < 3.3 空指针访问成员函数 C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性#include3.4 const修饰成员函数using namespace std; // class person { public: void showclassname() { cout << "this is person class" << endl; } void showpersonage() { //报错原因是因为传入的指针为空指针 if (this == NULL) //加上这个就可以了 { return; } cout<<"age=" < showclassname(); p->showpersonage(); } int main() { test01(); system("pause"); return 0; }
常函数 常对象 成员函数后加const后我们称为这个函数为常函数 声明对象前加const称该对象为常对象 常函数内不可以修改成员属性 常对象只能调用常函数 成员属性声明时加关键字mutable后,在常函数中依然可以修改 #include4.友元using namespace std; // class person { public: //常函数 // this 指针本质为指针常量,指向不可以修改 // const person * const this ; == this指针 // 在成员函数后面加上const之后,修饰的是this的指向,让指针指向的值也不可以修改 void showperson() const { //this 指针是 隐含在每一个非静态成员函数中的 一种指针 //this->m_a = 100; //this = NULL; //this 指针是不可以修改指针的指向的 this->m_b = 100; } int m_a; mutable int m_b; //特殊变量,即使在常函数中,也可以修改这个值。加上关键字mutable }; void test01() { person p; p.showperson(); cout << "good baby" << endl; } //常对象 void test02() { const person p2; //在对象前加const,变成了常对象 //p2.m_a = 100; p2.m_b = 100; // m_b是特殊值,在常对象里面也可以修改的 //常对象只可以调用常函数 } int main() { test01(); system("pause"); return 0; } 生活中你的家有客厅(Public),有你的卧室(Private)
4.1全局函数做友元
客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去但是呢,你也可以允许你的好闺蜜好基友进去。
在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类访问另—个类中私有成员
友元的关键字为friend
友元的三种实现: .全局函数做友元 ·类做友元 ·成员函数做友元#include4.2类做友元using namespace std; //建筑物的类 class building { //goodgay 是building好朋友 可以访问私有成员 friend void goodgay(building* building); public: building() { m_sittingroom = "客厅"; m_bedroom = "卧室"; } public: string m_sittingroom; //客厅 private: string m_bedroom; //卧室 }; //全局函数 void goodgay(building *b) { cout <<"好基友全局函数 正在访问" < m_sittingroom < m_bedroom << endl; //私有怎么访问 } void test01() { building b2; goodgay(&b2); } int main() { test01(); system("pause"); return 0; } #include4.3成员函数做友元using namespace std; //建筑物的类 class Building; class goodgay { public: goodgay(); void visit(); //参观函数 访问building中的属性 Building * building; private: }; class Building { friend class goodgay; // goodgay类是本类的好朋友,可以访问私有成员 public: Building(); //初始化 public: string m_sittingroom; private: string m_bedroom; }; //类外写成员函数 Building::Building() { m_sittingroom = "客厅"; m_bedroom = "卧室"; } goodgay::goodgay() { //创建建筑物的对象 building = new Building; } void goodgay::visit() { cout<<"好基友正在访问:" < m_sittingroom << endl; cout << "好基友正在访问:" << building->m_bedroom << endl; } void test01() { goodgay gg; gg.visit(); } int main() { test01(); system("pause"); return 0; } #include5运算符重载 5.1加号运算符重载using namespace std; // class Building; class goodgay { public: goodgay(); void visit(); //参观函数 访问building中的私有的成员 void visit2(); //参观函数 不访问building中的私有的成员 Building* building; }; class Building { //告诉编译器 goodgay类下的visit成员函数作为本类的好朋友,可以访问私有成员 friend void goodgay::visit(); public: Building(); public: string m_sittingroom; private: string m_bedroom; }; //类外写成员函数 Building::Building() { m_sittingroom = "客厅"; m_bedroom = "卧室"; } goodgay::goodgay() { //创建建筑物的对象 building = new Building; } void goodgay::visit() { cout << "visit函数正在访问:" << building->m_sittingroom << endl; cout << "visit函数正在访问:" << building->m_bedroom << endl; } void goodgay::visit2() { cout << "visit2函数正在访问:" << building->m_sittingroom << endl; //cout << "visit2函数正在访问:" << building->m_bedroom << endl; } void test01() { goodgay gg; gg.visit(); gg.visit2(); } int main() { test01(); system("pause"); return 0; } 三种重载方法!
#include5.2左移运算符重载using namespace std; class person { public: //1 成员函数重载+号 person operator+(person & p) { person temp; temp.m_a = this->m_a + p.m_a; temp.m_b = this->m_b + p.m_b; return temp; } int m_a; int m_b; }; //2 全局函数重载+号 person operator+(person& p1, person& p2) { person temp; temp.m_a = p1.m_a + p2.m_a; temp.m_b = p1.m_b + p2.m_b; return temp; } //函数重载的版本 person operator+(person& p1, int num) { person temp; temp.m_a = p1.m_a + num; temp.m_b = p1.m_b + num; return temp; } void test01() { person p1; p1.m_a = 10; p1.m_b = 10; person p2; p2.m_a = 10; p2.m_b = 10; //成员函数重载本质 person p3 = p1.operator+(p2); //person p3 = p1 + p2; //全局函数重载本质 person p3 = operator+(p1, p2); //person p3 = p1 + p2; //运算符重载,也可以发生函数重载 person p4 = p1 + 10; //person + int cout <<"p3.m_a" << p3.m_a << endl; cout <<"p3.m_b" << p3.m_b << endl; cout << "p4.m_a" << p3.m_a << endl; cout << "p4.m_b" << p3.m_b << endl; } int main() { test01(); system("pause"); return 0; } 输出自定义数据类型
#includeusing namespace std; class person { friend ostream& operator<<(ostream& cout, person p); friend void test01(); public: // 1 处成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p< 5.3递增运算符重载 #includeusing namespace std; //重载++运算符 //前置和后置++运算符 class myinterger { friend ostream& operator<<(ostream& cout, myinterger myint); //好朋友友元 public: myinterger() { m_num = 0; } //重载前置++运算符 返回引用是为了一直对一个数据进行操作 myinterger & operator++() { //先进行++的运算 m_num++; //再将自身返回 return *this; } //重载后置++运算符 myinterger operator++(int) //int让编译器知道你用的是后置运算符重载。 //int 代表占位参数,可以用来区分前置和后置的递增 { //先 记录当时的结果 myinterger temp = *this; //后 递增 m_num++; //最后将记录的结果进行返回的操作 return temp; } private: int m_num; }; //重载左移运算符 ostream& operator<<(ostream& cout, myinterger myint) //本质 operator<<(cout,p) 简化 cout << p { cout << myint.m_num; return cout; } void test01() { myinterger myint; cout< 5.4赋值运算符重载 #include5.5关系运算符重载using namespace std; // class person { public: person(int age) { m_age = new int(age); cout << "取" << endl; cout << this->m_age << endl; } ~person() { if (m_age != NULL) { delete m_age; m_age = NULL; cout <<"析构" << endl; } } //重载赋值运算符 person & operator=(person& p) { //编译器提供浅拷贝 //m_age = p.m_age; //应该先判断是否有属性在堆区,先释放干净在执行深拷贝 cout << this->m_age << endl; if (m_age != NULL) //将p2的的堆区数据清空,然后放入p1的数据!!!!!!!!!!!!!!! { delete m_age; m_age = NULL; cout << "释放" << endl; cout << this->m_age << endl; } //深拷贝 m_age = new int(*p.m_age); //返回对象本体 cout << this->m_age << endl; return *this; } int* m_age; }; void test01() { person p1(19); person p2(20); person p3(30); p3 = p2 = p1; cout << "p1的年龄为" << *p1.m_age << endl; cout << "p2的年龄为" << *p2.m_age << endl; cout << "p3的年龄为" << *p3.m_age << endl; } int main() { test01(); system("pause"); return 0; } #include5.6函数调用运算符重载using namespace std; // class person { public: person(string name, int age) { m_name = name; m_age = age; } //重载 == 号 bool operator==(person& p) { if (this->m_name == p.m_name && this->m_age == p.m_age) { return true; } return false; } //重载 != 号 bool operator!=(person& p) { if (this->m_name == p.m_name && this->m_age == p.m_age) { return false; } return true; } string m_name; int m_age; }; void test01() { person p1("tom", 18); person p2("jack", 22); if (p1 == p2) { cout << "p1 和p2 是相等的" << endl; } else { cout <<"布线等" << endl; } if (p1 != p2) { cout << "p1 和p2 是相等的" << endl; } else { cout << "布线等" << endl; } } int main() { test01(); system("pause"); return 0; } 函数调用运算符()也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活#includeusing namespace std; //打印输出类 class myprint { public: //重载函数调用运算符 void operator()(string test) { cout << test<< endl; } }; void myprint02(string test) { cout <



