目录
1.类的引入
2.类的定义
3.类的访问限定符及封装
3.1访问限定符
编辑
编辑
3.2封装
4类的作用域
5.类的实例化
6.类的对象大小的计算
6.1如何计算类对象的大小
6.2类对象的存储方式猜测
6.3 结构体内存对齐规则
7.this指针
7.1this指针的引出
7.2this指针的特性
1.类的引入
C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:
之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,
会发现struct中也可以定义函数。
#include<iostream>
using namespace std;
typedef int DataType;
struct Stack
{
void Init(size_t capacity)
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if (nullptr == _array)
{
perror("malloc申请空间失败");
return;
}
_capacity = capacity;
_size = 0;
}
void Push(const DataType& data)
{
// 扩容
_array[_size] = data;
++_size;
}
DataType Top()
{
return _array[_size - 1];
}
void Destroy()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
DataType* _array;
size_t _capacity;
size_t _size;
};
int main()
{
Stack s;
s.Init(10);
s.Push(1);
s.Push(2);
s.Push(3);
cout << s.Top() << endl;
s.Destroy();
return 0;
}
2.类的定义
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分
号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内
联函数处理。
class Person { //人
public:
void showInfo()
{
cout << _name << "-" << _sex << _age << endl;
}
public :
char* _name; //姓名
char* _sex; //性别
int _age; //年龄
};
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
成员变量命名规则建议:::::
class Date
{
public:
void Init(int year)
{
_year = year;
}
private:
int _year;
};
或者这样也可以::::
class Date
{
public:
void Init(int year)
{
mYear = year;
}
private:
int mYear;
};
3.类的访问限定符及封装
3.1访问限定符
C++ 通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限(也称为可见性),分别表示:公有的、受保护的、私有的。所谓访问权限,就是能不能使用该类中的成员。
public:可以被该类中的函数、子类的函数、友元函数访问,也可以由该类的对象访问;protected:可以被该类中的函数、子类的函数、友元函数访问,但不可以由该类的对象访问;
private:可以被该类中的函数、友元函数访问,但不可以由子类的函数、该类的对象、访问。
如果声明不写 public、protected、private,则默认为 private;
【面试题】问题: C++ 中 struct 和 class 的区别是什么?解答: C++ 需要兼容 C 语言,所以 C++ 中 struct 可以当成结构体使用。另外 C++ 中 struct 还可以用来定义类。和 class 定义类是一样的,区别是 struct 定义的类默认访问权限是 public , class 定义的类默认访问权限是 private 。注意:在继承和模板参数列表位置, struct 和 class 也有区别,后序给大家介绍。
我们先拿struct举例子
struct test
{
void PrintShow()
{
cout << _year<<" - " << _month << " - " << _day << endl;
}
private:
int _year = 1;
int _month = 2;
int _day = 3;
};
int main()
{
test t1;
t1.PrintShow();
return 0;
}
我们先拿class举例子
由此我们可以看出:struct定义的类默认访问权限是public,class定义的类是private
3.2封装
4类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::作用域操作符指明成员属于哪个类域。
5.类的实例化
class Person
{
public:
void showInfo();
public:
char* _name[20];
char* _gender[20];
int _age;
};
int main()
{
Person man;
man.showInfo();
man._age;
man._gender;
man._name;
return 0;
}
6.类的对象大小的计算
6.1如何计算类对象的大小
class A {
public:
void Print()
{
cout << _a << endl;
}
private:
char _a;
};
int main()
{
cout << sizeof(A) << endl;
return 0;
}
问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算 一个类的大小?
6.2类对象的存储方式猜测
C语言中结构体的对齐-》-》-》-》-》
我们介于一下三种猜想!!
- 对象中包含类的成员变量
-
代码只保存一份,在对象中保存存放代码的地址
- 只保存成员变量,成员函数存放在公共的代码段
结论:一个类的大小,实际就是该类中 ” 成员变量 ” 之和,当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
6.3 结构体内存对齐规则
1. 第一个成员在与结构体偏移量为 0 的地址处。2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS 中默认的对齐数为 83. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
7.this指针
7.1this指针的引出
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;
};
int main()
{
Date d1,d2;
d1.Init(2008, 12, 12);
d2.Init(2000, 11, 11);
d1.Print();
d2.Print();
return 0;
}
对于上述类,有这样的一个问题:Date 类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当 d1 调用 Init 函数时,该函数是如何知道应该设置 d1 对象,而不是设置 d2 对象呢?C++ 中通过引入 this 指针解决该问题,即: C++ 编译器给每个 “ 非静态的成员函数 “ 增加了一个隐藏的指针参数,让该指针指向当前对象 ( 函数运行时调用该函数的对象 ) ,在函数体中所有 “ 成员变量 ”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成 。
7.2this指针的特性
1. this 指针的类型:类类型 * const ,即成员函数中,不能给 this 指针赋值。2. 只能在 “ 成员函数 ” 的内部使用3. this 指针本质上是 “ 成员函数 ” 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以 对象中不存储 this 指针 。4. this 指针是 “ 成员函数 ” 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传递,不需要用户传递
编译器处理成员函数隐藏this指针
void Display()
{
cout<<_year<<endl;
}
// 底层
void Display(Date* this)
{
cout<<this->_year<<endl;
}
面试题
1.this指针存在哪里?
其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。类的静态成员函数因为没有this指针这个参数,所以类的静态成员函数也就无法调用类的非静态成员变量。2.this指针可以为空吗?
可以为空。当我们在调用函数的时候,如果函数内部不需要通过this指向当前对象并对其进行操作时才可以为空(当我们在其中什么都不放或者在里面随便打印一个字符串);如果调用的函数需要指向当前对象,并进行操作,则会发生错误(空指针引用)。