一.对象模型和this指针
1.成员变量和成员函数分开储存:
在c++中,成员变量和成员函数是分开储存的,且只有 非静态成员变量 才属于一个对象。
1.空对象占用内存:
class Person
{
};
int main()
{
Person p;
cout << sizeof(p) << endl;//1
return 0;
}
空对象会有一个字节的空间,是为了区分空对象栈内存的位置。
2.静态成员变量和成员函数不在类的对象上:
class Person
{
int a;//非静态成员变量,在对象上
static int b;//静态成员变量、不在
void func() {//成员函数,不在
}
};
int main()
{
Person p;
cout << sizeof(p) << endl;//4
return 0;
}
2.this指针:
this指针指向被调用的成员函数所属的对象。
不需要定义,直接用即可。
用途:
1.解决名称冲突
class Person {
public:
int age;
Person(int age)
{
age = age;
}
};
int main()
{
Person p1(18);
cout << p1.age << endl;//随机数,名称冲突时并没有赋值
return 0;
}
可用this指针解决:
class Person {
public:
int age;
Person(int age)
{
this->age = age;//用this
}
};
int main()
{
Person p1(18);
cout << p1.age << endl;//18
return 0;
}
2.返回对象本身用*this
例:
class Person {
public:
int age;
Person(int age)
{
this->age = age;//用this
}
Person& PersonAddAge(Person& p)
{
this->age += p.age;//自身年龄加上传入的对象的年龄
return *this;//返回一个对象自己
}
};
int main()
{
Person p1(18);
Person p2(18);
p2.PersonAddAge(p1).PersonAddAge(p1);//连续相加
cout << p2.age << endl;//36
return 0;
}
注:上面PersonAddAge函数返回的是引用Person&
如果把 & 去掉,只会加一次,
因为返回时返回的不是本体,而是拷贝构造后的新对象,后续相加就不是加在p2上了。
3.空指针访问成员函数:
空指针可以访问不引用成员变量的成员函数,
如果访问的成员函数引用了成员变量,则会报错。
class Person
{
public:
void showClassName()
{
cout << "Person class" << endl;
}
void showPersonAge()
{
cout << "age = " << m_age << endl;
}
int m_age;
};
void test01()
{
Person* p = NULL;
p->showClassName();//不报错
p->showPersonAge();//错误,无法从空对象找到其中属性
}
解决方法:可在引用了成员变量的函数中加上一个判定,使代码更健壮。
判断:this == NULL
void showPersonAge()
{
if (this == NULL)
{
return;
}
cout << "age = " << m_age << endl;
}
4.const修饰成员函数:
常函数:
1.成员函数后加const后称为常函数
2.常函数内不可以修改成员属性
3.成员属性声明时佳关键词mutable后,在常函数中可以修改
本质:在成员函数后面加const,修饰的是this指向,让指针指向的值也不可修改。
例:
class Person {
public:
void showPerson()const
{
m_A = 100;//报错,不可修改
m_B = 100;//可以修改
}
int m_A;
mutable int m_B;
};
常对象:
1.声明对象前加const称该对象为常对象
2.常对象中的属性不可修改
3.常对象只能调用常函数
class Person {
public:
void showPerson()const
{
}
void func()
{
}
int m_A;
mutable int m_B;
};
int main()
{
const Person p;
p.m_A = 100;//不可修改
p.m_B = 100;//可以修改
p.showPerson();
p.func();//报错,不能引用
return 0;
}
二.友元
友元的目的是让一个函数或者类访问另一个类中私有成员。
关键字:friend
1.全局函数作友元:
只需将函数在类中声明,再在函数前加上关键字 friend 即可。
class Building
{
//友元的声明,是使全局函数可以访问私有成员
friend void goodGay(Building* building);
public:
Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
//全局函数
void goodGay(Building* building)
{
cout << building->m_SittingRoom << endl;
cout << building->m_BedRoom << endl;
}
2.类作友元:
将一个类作为友元,即可在友元类中的函数访问此类中的私有成员。
class Building
{
friend class GoodGay;//GoodGay类可以访问私有成员
public:
Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
class GoodGay
{
public:
Building* building;
void visit();//参观函数,访问building中的属性
GoodGay()
{
building = new Building;
}
};
void GoodGay::visit()
{
cout << "访问" << building->m_BedRoom << endl;
}
3.成员函数作友元:
注意:需将友元函数所在类在前面定义。(GoodGay在Building之前定义)
class GoodGay
{
public:
Building* building;
void visit();//参观函数,访问building中的属性
GoodGay()
{
building = new Building;
}
};
class Building
{
friend void GoodGay::visit();//将成员函数作为友元
public:
Building()
{
m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
public:
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
void GoodGay::visit()
{
cout << "访问" << building->m_BedRoom << endl;//可以访问私有成员
}