类
c++新增了class关键字定义类,用法与struct类似,但是c++兼容c,所以struct不仅可以定义类,依旧可以当成结构体使用,他们定义类的时候区别是,struct默认访问是public,class默认访问是private。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
class类的两种定义
声明和定义全部放在类体中
如这种,如果成员函数类中定义,可能会被编译器当为内联函数处理。
class Person
{
public:
void showInfo()
{
cout << *_name << "-" << _age << endl;
}
private:
int _age;
char* _name;
};
声明和定义分离
这里就涉及到类的作用域,类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::作用域操作符指明成员属于哪个类域。
如上图,如果showInfo不指定去Person的域里查找,就只会在临时域和全局域中查找。
类的访问限定符及封装
访问限定符说明
1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为private,struct为public(因为struct要兼容C)
类的封装
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。实质上就是管理,让用户更方便使用。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
类对象模型
拿上面的代码举例
class Person
{
public:
void showInfo()
{
cout << *_name << "-" << _age << endl;
}
private:
int _age;
char* _name;
};
这个代码通过sizeof计算得出16字节(64位),这个可以看出类的大小并没有算上成员函数的大小
下面看其他情况的类的存储情况
// 类中既有成员变量,又有成员函数
class A1 {
public:
void f1() {}
private:
int _a;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类
class A3
{};
没有成员变量的类比较特殊,编译器会给这个类一个字节来标识这个类的对象存在过。
对于上面的类,如果我们将类实例化为多个对象,实际上这些对象不同的地方只有它的属性,它们调用的方法都是完全相同的,为了不重复保存这些代码,C++只保存了属性,而将方法放到了公共的代码段中,来避免了空间的浪费。
this指针
void Person::showInfo()
{
cout << "showInfo" << endl;
}
int main()
{
Person A1;
Person* a = &A1;
a->showInfo();
Person* b = nullptr;
b->showInfo();
}
上面这个代码会正常运行输出两个showInfo,而不会报错或者崩溃,因为成员函数不是存在对象中,所以上面代码不会对空指针解引用,也就不会崩溃报错
class Person
{
public:
void showInfo()
{
cout << _age << endl;
}
private:
int _age;
};
int main()
{
Person* b = nullptr;
b->showInfo();
}
上面代码把隐含的this指针加进去就会变成下面的代码
class Person
{
public:
void showInfo(Person* const this)
{
cout << this->_age << endl;
}
private:
int _age;
};
int main()
{
Person* b = nullptr;
b->showInfo(b);
}
现在的这个代码就可以明显看出来在打印输出时解引用了this指针,而this指针就是接收了nullptr的空指针,所以这个代码会崩溃。
在c++中编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
特性
1.这个this指针的类型是类类型* const this,之所以是顶层const的原因是因为this指针唯一指向对象地址。
2.this指针只能在成员函数中使用
3.this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针,this指针存在寄存器或是栈中。
4.this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。