C++类和对象(1)
C++类和对象(1)
- 1.类的定义
- 2.访问限定符
- 3.类域
- 4.对象的大小
- 5.this指针
如果我想把人这个对象封装起来。
经过C语言的学习,我们可以使用结构体,里面可以定义人的种种数据。
但是如果这个人的一些数据是涉及隐私的,不想让用户知道的,该怎么办呢?
这就是今天我们学习的类与结构体的核心区别。
1.类的定义
如果是结构体,我们这样定义。
struct Date
{int _year;int _month;int _day;};
如果是类,我们这样定义。
class Date {
public:void Init(int year, int month, int day) {_year = year;_month = month;_day = day;}//成员函数void Print() {cout << _year << "/" << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;//成员变量
};
class为类的关键字,后面是类名,{}中是类的主体。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量,类中的函数称为类的方法或成员函数。
因为有了在成员变量前面加了private:所以我们在除了类中的所有地方都不能直接访问这个类的成员函数。
成员函数默认为inline
2.访问限定符
分为三个:public,private,protected
在现阶段的学习中我们可以暂且认为private与protected作用一样。
class定义成员时没有被访问限定符修饰时默认为private
3.类域
类定义出了一个新的作用域。在类外定义成员时,需要加上::作用域操作符指明成员属于哪个类域
class Date {
public:void Init(int year, int month, int day) {_year = year;_month = month;_day = day;}void Print();
private:int _year;int _month;int _day;
};
void Date::Print() {cout << _year << "/" << _month << '/' << _day << endl;
}
4.对象的大小
在C语言学习时,我们学习了如何判断结构体的大小与内存对齐规则。
C++也规定实例化的对象要符合内存对齐的规则。
- 第一个成员在于结构体偏移量为0的地址处
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
- 对齐数 =(编译器默认的一个对齐数)与(该成员大小)的较小值
- vs中默认对齐数是8
- 最大对齐数 =(所有变量类型最大者)与(默认对齐数)取较小
- 结构体总大小为最大对齐数的整数倍
注意:
对象中不存储成员函数,因为函数被编译后是一段指令,它们无法存储在对象中。这些指令存储在单独的区域(代码段)。
#include<iostream>
using namespace std;
// 计算⼀下A/B/C实例化的对象是多⼤?
class A
{
public:void Print(){cout << _ch << endl;}
private:char _ch;int _i;
};
class B
{
public:void Print(){//...}
};
class C
{
};
int main()
{A a;B b;C c;cout << sizeof(a) << endl;cout << sizeof(b) << endl;cout << sizeof(c) << endl;return 0;
}
为什么b和c的大小是1呢?完全是因为要代表这个对象存在,不得不分配一个字节来说明其存在。
5.this指针
以上面的Date类为例,当我们创建了两个对象的d1.d2并调用成员函数时,该函数是如何知道应该访问d1还是d2呢?
编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this指针。比如Date类的Init的真实原型:
void Init ( Date* const this, int year, int month, int day )
- 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this->_year = year;
- C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。
所以其实void Init( int year, int month, int day)就等价于
void Init(Date* const this, int year, int month, int day)
接下来是两道经典例题
#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << "A::Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}
A.编译报错 B.运行崩溃 C.正常运行
注意:
当指针指向的内容是对象时,用它调用类中变量和函数的本质(类似p->Print())是将自己传给this指针。并非真正的解引用。
当我们调试转到反汇编时:
所以p->Print();实际上并没有发生解引用这一步,自然不会报错。
所以选C
#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << "A::Print()" << endl;cout<<_a<<endl;}
private:int _a;
};
int main()
{A* p =nullptr;p->Print();return 0;
}
A.编译报错 B.运行崩溃 C.正常运行
在Print函数中,_a就是this->_a,而p指针是空指针,所以this也是空指针,所以会运行错误。
完
如有错误,欢迎打在评论区。
主页还有更多优质内容OvO