在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上。
#include
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;
cout << "size of p==" << sizeof(p) << endl;
}
int main() {
test02();
system("pause");
return 0;
}
我们知道在C++中成员变量和成员函数是分开存储的
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码那么问题是:这—块代码是如何区分那个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的—种指针
this指针不需要定义,直接使用即可
this指针的用途:·当形参和成员变量同名时,可用this指针来区分 ·在类的非静态成员函数中返回对象本身,可使用return *this
#include
using 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的年龄" <<p1.age<< endl;
}
//2 返回对象本身用 return *this
void test02()
{
person p1(18);
person p2(18);
//链式编程思想 &personaddage 为了套猴
p2.personaddage(p1).personaddage(p1).personaddage(p1);
cout << "p2的年龄" << p2.age << endl;
}
int main() {
//test01();
test02();
system("pause");
return 0;
}
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性
#include
using namespace std;
//
class person
{
public:
void showclassname()
{
cout << "this is person class" << endl;
}
void showpersonage()
{
//报错原因是因为传入的指针为空指针
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;
}
常函数 | 常对象 |
---|---|
成员函数后加const后我们称为这个函数为常函数 | 声明对象前加const称该对象为常对象 |
常函数内不可以修改成员属性 | 常对象只能调用常函数 |
成员属性声明时加关键字mutable后,在常函数中依然可以修改 |
#include
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)
客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去但是呢,你也可以允许你的好闺蜜好基友进去。
在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类访问另—个类中私有成员
友元的关键字为friend
友元的三种实现: .全局函数做友元 ·类做友元 ·成员函数做友元
#include
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 <<"好基友全局函数 正在访问" <<b->m_sittingroom <<endl;
cout << "好基友全局函数 正在访问" << b->m_bedroom << endl; //私有怎么访问
}
void test01()
{
building b2;
goodgay(&b2);
}
int main() {
test01();
system("pause");
return 0;
}
#include
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<<"好基友正在访问:" <<building->m_sittingroom << endl;
cout << "好基友正在访问:" << building->m_bedroom << endl;
}
void test01()
{
goodgay gg;
gg.visit();
}
int main() {
test01();
system("pause");
return 0;
}
#include
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;
}
三种重载方法!
#include
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;
}
输出自定义数据类型
#include
using namespace std;
class person
{
friend ostream& operator<<(ostream& cout, person p);
friend void test01();
public:
// 1 处成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p<
//不会利用成员函数重载<<运算符,因为无法实现 cout在左侧
//void operator<<(person& p)
//{
//}
private:
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;
p.m_a = 10;
p.m_b = 10;
//链式编程思想
cout << p<<endl;
}
int main() {
test01();
system("pause");
return 0;
}
#include
using 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<<myint <<endl;
}
//重载后置++运算符
void test02()
{
myinterger myint;
cout << myint++ << endl;
cout << myint << endl;
}
//前置递增返回引用,后置递增返回值
int main() {
test02();
system("pause");
return 0;
}
#include
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;
}
#include
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;
}
函数调用运算符()也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活
#include
using namespace std;
//打印输出类
class myprint
{
public:
//重载函数调用运算符
void operator()(string test)
{
cout << test<< endl;
}
};
void myprint02(string test) {
cout <<test <<endl;
}
void test01()
{
myprint myprint;
myprint("hello world"); //由于使用起来非常类似于函数调用,因此称为仿函数
myprint02("hello world");
}
//仿函数非常灵活,没有固定的写法 test01, test02
//加法类
class Myadd
{
public:
int operator()(int num1, int num2)
{
return num1, num2;
}
};
void test02()
{
Myadd myadd;
int ret = myadd(100, 100);
cout <<"ret = " << ret<< endl;
//匿名函数对象 运行玩一次就会被释放掉
cout << Myadd()(100, 100) << endl;
}
int main() {
test02();
system("pause");
return 0;
}