面向对象编程自学笔记整理
十一_二、类与对象
3、对象模型和this指针
/*******************1.成员变量和成员函数分开储存******************************/
//#include<iostream>
//using namespace std;
//
//class person
//{
// int m_A;//非静态成员变量,属于类的对象上
//
// static int m_B;//静态成员变量(类内声明).不属于类的对象上
//
// void func(){}//非静态成员函数,不属于类的对象上
//
// static void func2() {}//静态成员函数,不属于类的对象上
//};
//int person::m_B=0;//静态成员变量(类外初始化)
//
//
//void test01()
//{
// //空对象所占的内存空间为:1
// //C++编译器会给每一个空对象分配一个字节的空间,为了区分空对象占内存的位置
// //每个空对象也应该有一个独一无二的内存空间
// person p;
// cout << "sizeof(p)=" << sizeof(p) << endl;
//}
//
//void test02()
//{
// person p;
// cout << "sizeof(p)=" << sizeof(p) << endl;
//}
//int main()
//{
// //test01();
// test02();
// system("pause");
// return 0;
//}
/*******************2.this指针******************************/
//#include<iostream>
//using namespace std;
//
this 指针的用途
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回 对象本身,可用return *this
//class person
//{
//public:
// person(int age)//构造函数
// {
// //this指针指向被调用的成员函数 所属的对象
// this->age = age;
// }
// //值的方式返回,会创建一个新的对象
// //引用的方式返回,不会创建一个新对象,会一直返回p2
// person& personaddage(person &p)
// {
// this->age += p.age;
// //this指向p2的指针,*this指向的就是p2的本体
// return *this;
// }
// int age;
//
//};
1解决名称冲突
//void test01()
//{
// person p1(18);
// cout << "p1年龄为:" << p1.age << endl;
//}
//
2返回对象本身用*this
//void test02()
//{
// person p1(10);
// person p2(10);
// //链式编程思想
// p2.personaddage(p1).personaddage(p1).personaddage(p1);
// cout << "p2的年龄为:" << p2.age << endl;
//}
//
//int main()
//{
// //test01();
// test02();
// system("pause");
// return 0;
//}
/*******************3.空指针调用成员函数******************************/
//#include<iostream>
//using namespace std;
//
//class person
//{
//public:
// void showclassName()
// {
// cout << "this is person class" << endl;
// }
// void showpersonAge()
// {
// //报错原因是传入的指针为空指针NULL
// if (this == NULL)
// {
// return;
// }//提高代码的鲁棒性
// cout << "age=" << this->m_age << endl;
// }
// int m_age;
//};
//
//void test01()
//{
// person* p = NULL;//创建一个空指针
// //p->showclassName();
// p->showpersonAge();
//}
//int main()
//{
// test01();
// system("pause");
// return 0;
//}
/*******************4.const修饰成员函数******************************/
//#include<iostream>
//using namespace std;
//
const修饰的为只读函数或者只读变量
//
常函数
成员函数后面加const我们称这个函数为常函数
常函数不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依旧可以修改
常函数
//class person
//{
//public:
// //this指针的本质:指针常量 指针指向不可以修改
// //person *const this;(指针常量)--指针指向不可以修改
// //const person *const this;指针的指向和指针指向的值都不可以修改
// //在成员函数后面加上const,修饰的是this指向,让指针指向的值也不可以修改
//
// void showperson() const//常函数
// {
// this->m_b = 100;
// //this->m_a = 100;//this指针指向的值也不可以修改
// //this = NULL;//this指针的指向不可以修改
// }
// void func()//普通函数
// {
// m_a = 100;
// }
// int m_a;
// mutable int m_b;//特殊变量,在常函数中也可以修改值,加关键字mutable
//};
//
//void test01()
//{
// person p;
// p.showperson();
//}
//
常对象
声明对象前加const称该对象为常对象
常对象只能调用常函数
常对象
//void test02()
//{
// const person p;//在对象前加const就是一个常对象
// //特点:不能修改指针指向的值
// //p.m_a = 100;
// p.m_b = 100;//特殊变量,在常对象中也可以修改值,加关键字mutable
// //常函数只能调用常对象
// p.showperson();//常对象可以调用常函数
// //p.func();//常对象不能调用普通函数,普通成员函数可以修改属性,而常对象不允许修改成员属性
//
//}
//
//
//int main()
//{
//
// system("pause");
// return 0;
//}
/*******************5.1友元——全局函数做友元******************************/
//友元目的:让一个函数或者类访问另一个类中的私有成员
//友元关键字:friend
//#include<iostream>
//using namespace std;
//#include<string>
//
建筑物类
//class building
//{
// //goodgay全局函数是building好朋友,可以访问building中私有成员
// friend void goodgay(building* building);
//public:
// building()//构造函数赋初值
// {
// m_settingroom = "客厅";
// m_badroom = "卧室";
// }
// string m_settingroom;//客厅
//private:
// string m_badroom;//卧室
//};
//
全局函数
//void goodgay(building* building)
//{
// cout << "好基友的全局函数正在访问:" << building->m_settingroom << endl;
// cout << "好基友的全局函数正在访问:" << building->m_badroom << endl;
//}
//
//void test01()
//{
// building building;
// goodgay(&building);
//}
//int main()
//{
// test01();
// system("pause");
// return 0;
//}
/*******************5.2友元——类做友元******************************/
//#include<iostream>
//using namespace std;
//#include<string>
//
类做友元
//class building;
基友类
//class goodgay
//{
//public:
// goodgay();//类外实现构造函数
// void visit();//参观函数,访问building中的属性
// building* buil;
//};
//
建筑类
//class building
//{
goodgay类是本类的好朋友,可以访问本类中的私有成员
// friend class goodgay;//(类作为友元)
//public:
// building();//类外实现构函数
// string m_settingroom;//客厅
//private:
// string m_badroom;//卧室
//};
//
类外写成员函数
//goodgay::goodgay()
//{
创建一个建筑物的对象
// buil = new building;//在堆区创建一个对象
//}
//
//void goodgay::visit()
//{
// cout << "好基友正在访问:" << buil->m_settingroom <<endl;
//
// cout << "好基友正在访问:" << buil->m_badroom << endl;
//}
//
//building::building()
//{
// m_settingroom = "客厅";
// m_badroom = "卧室";
//}
//
//void test01()
//{
// goodgay gg;
// gg.visit();
//}
//
//int main()
//{
// test01();
// system("pause");
// return 0;
//}
/*******************5.3友元——成员函数做友元******************************/
#include<iostream>
using namespace std;
#include<string>
class building;
class goodgay
{
public:
goodgay();//类外实现成员构造函数
void visit();//让visit函数可以访问building中的私有成员
void visit2();//让visit函数不可以访问building中的私有成员
building* buil;
};
//建筑类
class building
{
//告诉编译器,goodgay类下的visit成员函数可以作为本类的好朋友,访问私有成员
friend void goodgay::visit();
public:
building();//类外实现成员构造函数
string m_settingroom;//客厅
private:
string m_badroom;//卧室
};
//类外定义成员构造函数
goodgay::goodgay()
{
//在堆区创建一个building的对象
buil=new building;
}
void goodgay::visit()
{
cout << "visit函数正在访问:" << buil->m_settingroom << endl;
cout << "visit函数正在访问:" << buil->m_badroom << endl;
}
void goodgay::visit2()
{
cout << "visit2函数正在访问:" << buil->m_settingroom << endl;
//cout << "visit2函数正在访问:" << buil->m_badroom << endl;
}
building::building()
{
m_settingroom = "客厅";
m_badroom = "卧室";
}
void test01()
{
goodgay gg;
gg.visit();
gg.visit2();
}
int main()
{
test01();
system("pause");
return 0;
}
4、运算符重载
/*****************1.加号运算符重载*****************************************/
//#include<iostream>
//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 = 20;
// p2.m_B = 20;
//
// //成员函数重载本质调用
// //person p3 = p1.operator+(p2);
//
// //全局函数重载本质调用
// //person p3 = operator+(p1, p2);
//
// //person p3 = p1 + p2;//(简化形式)
// //cout << "p3.m_A=" << p3.m_A << endl;
// //cout << "p3.m_B=" << p3.m_B << endl;
//
// //运算符重载,也可以发生函数重载
// person p4 = p1 + 10;//(person+int)
// cout << "p4.m_A=" << p4.m_A << endl;
// cout << "p4.m_B=" << p4.m_B << endl;
//}
//int main()
//{
// test01();
// system("pause");
// return 0;
//}
/*****************2.左移运算符重载*****************************************/
//#include<iostream>
//using namespace std;
//
左移运算符重载
//class person
//{
//public:
// friend ostream& operator<<(ostream& cout, person& p);
// person(int a,int b)
// {
// m_A=a;
// m_B=b;
// }
//private:
//
// //利用成员函数重载左移运算符 p.operator<<(cout) 简化版本p<<cout
// //不会利用成员函数重载<<运算符,因为无法实现cout在左侧
// //void operator<<()
// //{}
// int m_A;
// int m_B;
//};
//
// //只能利用全局函数重载左移运算符
//ostream & operator<<(ostream & cout, person& p)//本质operator<<(cout,p)简化为cout<<p
//{
// cout << "m_A=" << p.m_A << "m_B=" << p.m_B;
// return cout;
//}
//
//void test01()
//{
// person p(10,10);
// cout << p <<"hello world" << endl;
//}
//int main()
//{
// test01();
// system("pause");
// return 0;
//}
/*****************3.递增运算符重载*****************************************/
//前置递增返回的是引用,后置递增返回的是值
//#include<iostream>
//using namespace std;
//
递增运算符重载
//void func()
//{
//int a = 10;
//cout << ++a << endl;//11(前先算再赋值)
//cout << a << endl;//11
//
//int b = 10;
//cout << b++ << endl;//10(后先赋值再算)
//cout << b << endl;;//11
//}
//
//class myinteger
//{
//public:
// friend ostream& operator<<(ostream& cout, myinteger myint);
// myinteger()
// {
// m_num = 0;
// }
// //重载前置++运算符,返回引用是为了一直对一个数据进行递增操作
// //前置递增返回的是一个引用
// myinteger & operator++()
// {
// //先进行++运算
// m_num++;
// //再将自身返回
// return *this;
// }
// //重载后置++运算符(后置递增返回的是值)
// myinteger operator++(int)//括号加int为后置运算符重载
// {
// //先记录当时的结果
// myinteger temp = *this;//*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;//0
// cout << ++myint << endl;//1
// cout << myint++ << endl;//1
// cout << myint << endl;//2
//}
//int main()
//{
// //func();
// test01();
// system("pause");
// return 0;
//}
/*****************4.赋值运算符重载*****************************************/
//#include<iostream>
//using namespace std;
//
c++编译器至少给一个类添加4个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝函数,对属性进行值拷贝(堆区空间重复释放)
4.赋值运算符 operator=对属性进行值拷贝(解决浅拷贝问题)
//
//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)
// {
// //编译器提供浅拷贝
// //m_age=p.m_age;
// //应该判断是否有属性在堆区,如果有先释放干净,再深拷贝
// if (m_age != NULL)
// {
// delete m_age;
// m_age = NULL;
// }
// //深拷贝
// 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;//赋值:将p1的值赋给p2
// //浅拷贝——简单的值拷贝和地址拷贝,导致堆区的内存重复释放,程序奔溃
// //解决方案:利用深拷贝解决堆区数据重复释放问题
// //深拷贝:开辟一块新内存,将数据复制到新内存中
// cout << "p1的年龄为:" << *p1.m_age << endl;
// cout << "p2的年龄为:" << *p2.m_age << endl;
// cout << "p3的年龄为:" << *p3.m_age << endl;
//
//}
//int main()
//{
// test01();
// //int a = 10;
// //int b = 20;
// //int c = 30;
// //c = b = a;
// //cout << "a=" << a << endl;
// //cout << "b=" << b << endl;
// //cout << "c=" << c << endl;
// system("pause");
// return 0;
//}
/*****************5.关系运算符重载*****************************************/
//重载关系运算符,让两个自定义的类型对象进行对此操作
//#include<iostream>
//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;
// else
// return false;
// }
// //重载!=号
// bool operator!=(person& p)
// {
// if (this->m_name == p.m_name || this->m_age == p.m_age)
// return false;
// else
// return true;
// }
//
//private:
// string m_name;
// int m_age;
//
//};
//
//void test01()
//{
// person p1("李明", 18);
// person p2("李明", 18);
// 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;
//}
/*****************6.函数调用运算符重载*****************************************/
//函数调用运算符()也可以重载
#include<iostream>
#include<string>
using namespace std;
//函数调用运算符重载;
//打印输出类
class myprint
{
public:
//重载的函数调用运算符
void operator()(string test)//重载小括号
{
cout << test << endl;
}
};
//加法类
class myadd
{
public:
int operator()(int num1, int num2)
{
return num1 + num2;
}
};
void test02()
{
myadd MD;
int ret=MD(2, 3);//仿函数
cout << "ret=" << ret << endl;
//创建匿名函数对象 类型+()
//特点:当前行被执行完空间被释放
cout << myadd()(10, 10) << endl;
}
void Myprint(string test)//正常打印函数
{
cout << test << endl;
}
void test01()
{
myprint MP;
MP("hello world!");//重载函数的调用运算符调用
//重载后的使用方式非常像函数的调用,因此称为仿函数
//仿函数没有固定的写法,非常灵活
Myprint("hello world");//正常打印函数调用函数
}
int main()
{
test01();
test02();
system("pause");
return 0;
}