目录
1. 面向过程和面向对象初步认识
2. 类的引入
3. 类的定义
4. 类的访问限定符及封装
4.1 访问限定符
4.2 封装
5. 类的作用域
6. 类的实例化
7. 类对象模型
8. this指针
8.1 this指针的引出
8.2 this指针的特性
没有坚持的努力,本质上并没有多大意义!
class ListNode
{
int _val;
//struct ListNode* next;//c语言的方式,C++也兼容
ListNode* _next;//C++的方式
};//因为struct被升级,结构体名称可以作类型
//这里的listNode我们叫做对象
命名规则建议:C++类的成员我们习惯在前面加一个_(来区分类的对象和别的参数)
class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
class Date
{
public:
void Init(int year)
{
_year = year;
}
private:
int _year;
};
访问限定符:public、private、protected1. public 修饰的成员在类外可以直接被访问2. protected 和 private 修饰的成员在类外不能直接被访问 ( 此处 protected 和 private 是类似的 )3. 访问权限 作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止4. 如果后面没有访问限定符,作用域就到 } 即类结束。5. class 的默认访问权限为 private , struct 为 public( 因为 struct 要兼容 C)
问题:C++中struct和class的区别是什么?解答: C++ 需要兼容 C 语言,所以 C++ 中 struct 可以当成结构体使用。另外 C++ 中 struct 还可以用来定义类。和class定义类是一样的,区别是 struct 定义的类默认访问权限是 public , class 定义的类默认访问权限是private。注意:在继承和模板参数列表位置, struct 和 class 也有区别.
注意:(1)C语言数据和方法是分离的;而C++数据和方法封装到类里面,想让别人访问的部分设成公有,不想让别人访问的设成私有。
(2)一般情况下,类的成员数据都是私有或者保护。想给别人访问的函数是共有的,不想让别人访问的函数是私有或者保护。
(3)封装本质上是一种管理。
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
//此时,这个函数的内容,相当于在类里面,所以可以用类中的对象(私有的也可以)
(1)在类里面定义的函数默认是inline函数。实际中,一般情况下,短小函数可以在类里面定义,长一点函数声明和定义分开。
(2)类成员变量仅仅只是声明。【声明没有开辟空间】
int main()
{
Person._age = 100; // 编译失败:error C2059: 语法错误:“.”
return 0;
}
int main()
{
Person man;//这里才给类定义空间
man._age = 100;
return 0;
}//这样才对
结论:一个类的大小,实际就是该类中 ”成员变量”之和 ,当然也要进行内存对齐,注意空类的大小,空类比 较特殊,编译器给了空类一个字节来唯一标识这个类。
知识点复习:结构体内存对齐1. 第一个成员在与结构体偏移量为 0 的地址处。2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS 中默认的对齐数为 83. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
【面试题】1. 结构体怎么对齐? 为什么要进行内存对齐?2. 如何让结构体按照指定的对齐参数进行对齐?3. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景 。
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.SetDate(2018, 5, 1);
d2.SetDate(2018, 7, 1);
d1.Printf();
d2.Printf();
return 0;
}
C++ 中通过引入 this 指针解决该问题,即: C++ 编译器给每个 “ 非静态的成员函数 “ 增加了一个隐藏的指针参 数,让该指针指向当前对象 ( 函数运行时调用该函数的对象 ) ,在函数体中所有 “ 成员变量 ” 的操作,都是通过该 指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成 。
以上代码:(1)d1和d2地址,和分别对应的this是一致的。
(2)this不能修改,this指向的变量可以修改。
1. this 指针的类型:类类型 * const ,即成员函数中,不能给 this 指针赋值,不能修改。2. 只能在 “ 成员函数 ” 的内部使用3. this 指针本质上是 “ 成员函数 ” 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给 this 形参。所以对象中不存储 this 指针 。4. this 指针是 “ 成员函数 ” 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传递,不需要用 户传递
【面试题】1. this 指针存在哪里?一般在栈区,有些编译器会使用寄存器优化,存放在寄存器。2. this 指针可以为空吗?可以的,但是不能解引用变量,可以是函数(函数在公共区域)
class A
{
public:
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Show();//这个不是解引用,因为函数在公共区域,并不是在空指针的位置,所以不会报错
}
//正常运行
class A
{
public:
void Show()
{
cout << "Show()" << endl;
}
int _a;
};
int main()
{
A* p = nullptr;
p->Show();//这个不是解引用,因为函数在公共区域,并不是在空指针的位置,所以不会报错
p->_a = 0;//这个是解引用,在类里,空指针,所以就会报错
}
//运行崩溃
class A
{
public:
void PrintA()
{
cout << _a << endl;//在这里进行空指针的解引用,报错
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
}
//运行崩溃