- C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题
- C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成
#includeusing namespace std; //C struct Stack_C { int* a; int top; int capacity; }; //C++ struct Stack_CPP { void Init() { a = 0; top = capacity = 0; } void Push(int x) { // ... } void Pop() { // ... } int* a; int top; int capacity; }; int main() { struct Stack_C st1; //Stack是类名,也是一种类型,直接用就行了 Stack_CPP st2; st2.Init(); st2.Push(1); st2.Push(2); st2.Push(3); return 0; }
- 在C语言中struct中只能定义成员变量
- 在C++中引入了类的概念,struct中不仅仅可以定义成员变量,还可以定义成员函数
#includeusing namespace std; class Person { //显示基本信息 void Show_information() { cout << _name << _age << _area << endl; } char* _name; char* _area; int _age; }; int main() { Person zhansan; return 0; }
- 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
- 类声明放在.h文件中,成员函数定义放在.cpp文件中,
- 注意:成员函数名前需要加类名::
- 小函数,想成为inline,直接在类里面定义就可以
- 如果是大函数,应该声明和定义分离
#include【访问限定符说明】using namespace std; class Stack { public: void Init() { a = 0; top = capacity = 0; } void Push(int x) { // ... } void Pop() { // ... } int Top() { return a[top - 1]; } private: //protected: int* a; int top; int capacity; }; int main() { Stack st; st.Init(); st.Push(1); st.Push(2); st.Push(3); //cout << st.a[st.top] << endl; //cout << st.a[st.top-1] << endl; cout << st.Top() << endl; //st.a = nullptr; return 0; }
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct为public(因为struct要兼容C)
- C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,封装 本质上是一种管理 ,让用户更方便使用类, 举个例子:取栈的栈顶
- C语言->没有办法封装,对于使用者来说这里的st.top可能是栈顶元素,也可能是栈顶的后一个元素,可以直接访问数据,但是不规范
- C++ -> 封装 必须规范使用函数访问数据,不能直接访问数据,
类不占用空间,在使用的时候发生类的实例化,才开辟了空间
- 规范的使用类的时候,是需要声明和定义分离的,开辟了空间叫定义,没有开辟空间的叫声明
- static 修饰的声明,只在当前文件可见,链接时没有放进符号表,所以两次打印的地址不同
- extern 修饰的声明,在链接时会放进符号表,所以两次打印的地址相同
- 注意:.h文件会在.cpp中展开,所以在.h文件中没有声明变量只定义变量,就会出现链接错误,重定义,
猜测一:对象中包含类的各个成员
- 缺陷:每个对象中成员变量是不同的,都调用同一份函数,每次调用相同的代码就会保存一次,多个对象的话,相同代码保存多次,浪费空间。
猜测二:代码只保存一份,在对象中保存存放代码的地址
- 这里在访问类成员函数的时候,是通过对象中保留了类成员函数表的指针,通过指针的解引用进行访问的,
猜测三:只保存成员变量,成员函数存放在公共的代码段
- 编译链接时就根据函数名去公共代码区找到函数地址
- C++类对象的存储方式是第三种,只保存成员变量,成员函数存放在公共的代码段
#includeusing namespace std; class A1 { public: void PrintA() { cout << _a << endl; } void func() { cout << "void A::func()" << endl; } private: char _a; int _i; }; class A2 { public: void f2() {} }; class A3{ }; int main() { cout << sizeof(A1) << endl; cout << sizeof(A2) << endl; cout << sizeof(A3) << endl; return 0; }
- 一个类的大小,实际就是该类中”成员变量”之和,这里和C语言一样也会发生内存对齐
- 注意:空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
驼峰法——单词和单词之间首字母大写间隔
class Date
{
public:
void Init(int year)
{
_year = year;
}
private:
int _year;
};
- 函数名、类名等所有单词首字母大写 DateMgr
- 变量首字母小写,后面单词首字母大写 dateMgr
- 成员变量,首单词前面加_ _dateMgr
#includeusing namespace std; 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; d1.Init(2022, 7, 17); Date d2; d2.Init(2022, 7, 18); d1.Print(); d2.Print(); return 0; }
- Date类中有 Init 与 Print 两个成员函数,他们都是放在 公共代码区 中的,而函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,lnit这个函数如何知道应该对d1进行初始化,而不是给d2进行初始化
-
C++中通过引入
this
指针解决该问题,即:
- C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,
- 让该指针指向当前对象 (函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该 指针去访问。
- 只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
#includeusing namespace std; class Date { public: void Init(Date* const this, int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; } void Print(Date* const this) { cout << this->_year << "-" << this->_month << "-" << this->_day << endl; } private: int _year; // 年 -> 声明 int _month; // 月 int _day; // 日 }; int main() { Date d1; d1.Init(&d1,2022, 7, 17); Date d2; d2.Init(&d2,2022, 7, 18); d1.Print(); d2.Print(); return 0; }
- 这里我将编译器隐藏起来的this指针显示出来了,但这样编译器是会报错的,
- 注意:实参和形参位置不能显示传递和接收this指针,但是可以在成员函数内部使用this指针
- this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
- 只能在“成员函数”的内部使用
- this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是“成员函数”第一个隐含的指针形参,vs下面传递是通过ecx寄存器传递的,这样this访问变量的时候可以提高效率,不过这些优化取决于编译器,
- 栈区,因为他是一个形参
#includeusing namespace std; class A { public: void Print() { cout << "Print()" << endl; //cout << this << endl; } private: int _a; }; int main() { A* p = nullptr; p->Print(); //正常运行 return 0; }
- 这段代码不会发生崩溃,编译报错的情况,它是会正常运行的
- p->Print如果对p进行了解引用,就会报错,但这里是正常运行的,可见类对象的存储方式是猜测三:只保存成员变量,成员函数存放在公共的代码段
#includeusing namespace std; class A { public: void Print(int x) { this->_a = x; cout << this->_a << endl; } private: int _a; }; int main() { A* p = nullptr; p->Print(1); //崩溃 return 0; }
- 这段代码会崩溃,空指针没有问题,但是对空指针进行接引用就会有问题



