旅游做攻略网站好,阜新网站设计,网站前台功能介绍,网站怎么做漂亮点三、C对象模型和this指针
3.1 成员变量和成员函数分开存储
在C中#xff0c;类内的成员变量和成员函数分开存储#xff0c;只有非静态成员变量才属于类的对象上
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace …三、C对象模型和this指针
3.1 成员变量和成员函数分开存储
在C中类内的成员变量和成员函数分开存储只有非静态成员变量才属于类的对象上
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using 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 sizeof(p) endl;
}
void test02() {Person p;//占用内存空间为 4 个字节cout size of p sizeof(p) endl;
}int main() {//test01();test02();system(pause);return 0;
}
3.2 this指针概念
通过上面我们知道在C中成员变量和成员函数是分开存储的每一个非静态成员函数只会诞生一份函数实例也就是说多个同类型的对象会共用一块代码那么问题是:这—块代码是如何区分那个对象调用自己的呢?
C通过提供特殊的对象指针, this指针解决上述问题的。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义直接使用即可
this指针的用途:
1.当形参和成员变量同名时可用this指针来区分
2.·当形参和成员变量同名时可用this指针来区分 #define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Person {
public:Person(int age) {//age age;这样写无法区分达到所需要求//this指针指向的是 被调用的成员函数所属的对象 即p1this-age age;}Person PersonAddAge(Person p) {this-age p.age;//this指向p2的指针而*this指向的就是p2,返回本体用//如果去掉就是返回值答案为20出来的是p2一个新的对象return *this;}//解决名称冲突int age;};void test01() {Person p1(18);cout p1的年龄为 p1.age endl;}
3.3 空指针访问成员函数
C中空指针也是可以调用成员函数的但是也要注意有没有用到this指针
如果用到this指针需要加以判断保证代码的健壮性
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Person {
public:void showClassName() {cout this is Person class endl;}void showPersonAge() {if (this NULL) {return;}cout age this-m_Age endl;}int m_Age;};void test01() {Person* p NULL;p-showClassName();//在新版VS里虽然能运行但是仍存在问题传入的指针为空p-showPersonAge();
}int main() {test01();system(pause);return 0;
}
3.4 const修饰成员函数
常函数:
·成员函数后加const后我们称为这个函数为常函数
·常函数内不可以修改成员属性
·成员属性声明时加关键字mutable后在常函数中依然可以修改
常对象:
·声明对象前加const称该对象为常对象
·常对象只能调用常函数
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Person {
public://常函数//this指针的本质 是指针常量 指针的指向是不可修改的//const Person * const this;//Person * const this 就是this在成员函数后面加const修饰的是this指向让指针指向的值也不可以修改void showPerson() const{//加上const则值也不可修改//this-m_A 100; 报错//this NULL; 已经指向 p不可修改this-m_B 100;}void func(){}int m_A;mutable int m_B;//特殊变量即使在常函数中也可以修改这个值
};void test01() {Person p;p.showPerson();
}//常对象
void test02() {const Person p;//在对象前加上const//p.m_A 100;不可修改p.m_B 100;//m_B是特殊的值在常对象下也可修改//常对象只能调用常函数//p.func();不可调用普通的成员函数因为普通的成员函数可以修改
}int main() {test01();test02();system(pause);return 0;
}
四、友元
生活中你的家有客厅(Public)有你的卧室(Private。客厅所有来的客人都可以进去但是你的卧室是私有的也就是说只有你能进去但是呢你也可以允许你的好闺蜜好基友进去。 在程序里有些私有属性也想让类外特殊的一些函数或者类进行访问就需要用到友元. 友元的目的就是让—个函数或者类访问另—个类中私有成员. 友元的关键字为friend 友元的三种实现:
·全局函数做友元
·类做友元
·成员函数做友元
4.1 全局函数做友元
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Buliding {//这样就可以使其函数访问私有成员friend void goodGay(Buliding* bulidding);
public:Buliding() {m_SittingRoom 客厅;m_BedRoom 卧室;}public:string m_SittingRoom;//客厅
private:string m_BedRoom;//卧室};void goodGay(Buliding *bulidding) {cout 好基友的全局函数 正在访问 bulidding-m_SittingRoom endl;cout 好基友的全局函数 正在访问 bulidding-m_BedRoom endl;
}void test01() {Buliding bulidding;goodGay(bulidding);}int main() {test01();system(pause);return 0;
}
4.2 类做友元
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Building;
class GoodGay {
public:GoodGay();void visit();Building * building;
};class Building {//这样GoodGay类的成员就可以访问本类的私有成员friend class 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 好基友的类正在访问 building-m_SittingRoom endl;cout 好基友的类正在访问 building-m_BedRoom endl;}void test01() {GoodGay gg;gg.visit();
}int main() {test01();system(pause);return 0;
}
4.3 成员函数做友元
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;class Building;
class GoodGay {
public:GoodGay();void visit();//让visit函数可以访问Building中私有成员void visit2();//让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;
}
五、运算符重载
运算符重载概念:对已有的运算符重新进行定义赋予其另一种功能以适应不同的数据类型
5.1 加号运算符重载
作用:实现两个自定义数据类型相加的运算
eg.
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;//加号运算符重载
class Person {public://1、成员函数重载 号成员函数重载本质调用//Person p3 p1.operator(p2);/*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 p3 operator(p1, p2);
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;p3 p1 p2;//运算符重载也可以发生函数重载Person p4 p1 100;cout p3.m_A p3.m_A endl;cout p3.m_B p3.m_B endl;cout p4.m_A p4.m_A endl;cout p4.m_B p4.m_B endl;
}int main() {test01();system(pause);return 0;
}
注意
1: 对于内置的数据类型的表达式的的运算符是不可能改变的
2: 不要滥用运算符重载
5.2 左移运算符重载较难
作用:可以输出自定义数据类型
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;//左移运算符重载
class Person {public://利用成员函数重载左移运算符//不会利用成员函数重载运算符因为无法实现cout在左侧//void operator(Person p) {// //两个对象了// //改为p.operator(cout) 简化版本 p cout//}int m_A;int m_B;
};///只能利用全局函数重载左移运算符ostream operator(ostream cout,Person p)//本质operator ( cout ,p )简化 cout p
{//全局只能有1个所以用coutcout m_A p.m_A m_B p.m_B;return cout;
}void test01() {Person p;p.m_A 10;p.m_B 10;cout p hello,word endl;
}int main() {test01();system(pause);return 0;
}
5.3 递增运算符重载
作用:通过重载递增运算符实现自己的整型数据
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;//重载递增运算符//自定义整型
class MyInteger {friend ostream operator(ostream cout, MyInteger myint);
public:MyInteger() {m_Num 0;}//重载前置运算符返回引用为了一直对一个数据讲行递增操作MyInteger operator() {m_Num;return *this;}//重载后置运算符//void operator(int) int代表占位参数可以用于区分前置和后置MyInteger operator(int) {//先记录当时结果MyInteger temp *this;//后递增m_Num;//最后将记录结果做返回return temp;}
private:int m_Num;};ostream operator(ostream cout, MyInteger myint) {cout myint.m_Num;return cout;
}void test01() {MyInteger myint;cout (myint) endl;
}
void test02() {MyInteger myint;cout myint endl;cout myint endl;
}int main() {test01();test02();system(pause);return 0;
}
5.4 赋值运算符重载
C编译器至少给一个类添加4个函数
1.默认构造函数(无参函数体为空)
2.默认析构函数(无参函数体为空)
3.默认拷贝构造函数对属性进行值拷贝
4.赋值运算符operator,对属性进行值拷贝 如果类中有属性指向堆区做赋值操作时也会出现深浅拷贝问题
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;//重载赋值运算符
class Person {
public:Person(int age) {m_Age new int(age);}~Person() {if (m_Age ! NULL) {delete(m_Age);m_Age NULL;}}Person operator(Person p) {//应该先判断是否有属性在堆区如果有先释放干净然后再深拷贝if (m_Age ! NULL) {delete m_Age;m_Age NULL;}this-m_Age new int(*p.m_Age);return *this;}int* m_Age;};void test01() {Person p1(18);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;
}
5.5 关系运算符重载
作用:重载关系运算符可以让两个自定义类型对象进行对比操作
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
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(Tom, 8);if (p1 p2) {cout p1和p2是相等的! endl;}else {cout p1和p2是不相等的! endl;}if (p1 ! p2) {cout p1和p2是不相等的! endl;}else {cout p1和p2是相等的! endl;}}int main() {test01();system(pause);return 0;
}
5.6 函数调用运算符()重载
·函数调用运算符()也可以重载
·由于重载后使用的方式非常像函数的调用因此称为仿函数
·仿函数没有固定写法非常灵活
#define _CRT_SECURE_NO_WARNINGS 1
#include iostream
#include string.h
using namespace std;//重载函数调用运算符
class MyPrint {
public://重载函数调用运算符void operator()(string test) {cout test endl;}
};void test02(string test) {cout test endl;}void test01() {MyPrint myPrint;myPrint(hello world!);//由于使用起来非常类似于函数调用因此称为仿函数test02(hello world!);
}//仿函数没有固定写法非常灵活
//加法类class MyAdd {
public:int operator()(int num1, int num2) {return num1 num2;}};void test03() {MyAdd myAdd;int ret myAdd(100, 100);cout ret ret endl;//匿名函数对象cout MyAdd()(100, 100) endl;
}int main() {test01();test03();system(pause);return 0;
}