- 1.内和对象
- 1.面向过程和面向对象初步认识
- 2.类的引入
- 3类的访问限定符
- 4.封装
- 5.类的作用域
- 6.类的实例化
- 7.类的运算
- 2.隐含的this指针
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
c语言是不是能这样写
struct student
{
char _name[20];
char _gender[3];
int _age;
};
但是c++就不只是这样了,c++把结构体升级引出了一个叫类的概念
C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数
// C++兼容C struct的用法
// C++同时对struct进行了升级,把struct 升级成了类
// 1、结构体名称可以做类型
// 2、里面可以定义函数
struct student
{
void Init(const char* name, const char* gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void printf()
{
cout << _name << " " << _gender << " " << _age << endl;
}
char _name[20];
char _gender[3];
int _age;
};
1、结构体名称可以做类型这个怎么理解
比如我们要写个链表的结构体
C语言
struct LisNode
{
int val;
struct LisNode* next;
};
C语言不能结构体名称做类型,c++可以
c++
struct LisNode
{
int val;
LisNode* next;
};
不过因为c++支持c所以用c的写法也是可以的
2.使用结构里面的函数
#define _CRT_SECURE_NO_WARNINGS 1 #includeusing namespace std; // C++兼容C struct的用法 // C++同时对struct进行了升级,把struct 升级成了类 // 1、结构体名称可以做类型 // 2、里面可以定义函数 struct student { void Init(const char* name, const char* gender, int age) { strcpy(_name, name); strcpy(_gender, gender); _age = age; } void printf() { cout << _name << " " << _gender << " " << _age << endl; } //这里不是必须加_ //是习惯用来表示成员变量 char _name[20]; char _gender[3]; int _age; }; int main() { student s1; s1.Init("zhangsan", "nan",18); return 0; }
这里还有一个问题,c++不是向上找的吗?为什么成员变量不放上面,其实这里成员变量放哪里都可以,只是这是一个类,可以把它看成一个整体
对于上面的代码c++更喜欢用class,而不是struct,就是
class student
{
};
而student s1;这个s1也不叫变量了,改成叫对象了
3类的访问限定符public限定符代表着它之后的都是公有的
class student
{
public:
void Init(const char* name, const char* gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void printf()
{
cout << _name << " " << _gender << " " << _age << endl;
}
//这里不是必须加_
//是习惯用来表示成员变量
char _name[20];
char _gender[3];
int _age;
};
int main()
{
student s1;
s1.Init("zhangsan", "nan",18);
s1.printf();
return 0;
}
把public注释了再运行一下
报错了,说无法访问,这是因为class本身就是私有的
换成struct可以编译过,说明struct是共有的
那么能不能在它们下面加访问限定符,答案是可以的
通常都是共有和私有一起用的,因为一串代码里面肯定有不想让人修改的代码
比如这样
class student
{
public:
void Init(const char* name, const char* gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void printf()
{
cout << _name << " " << _gender << " " << _age << endl;
}
private:
//这里不是必须加_
//是习惯用来表示成员变量
char _name[20];
char _gender[3];
int _age;
};
这样子就访问不了成员了,但是里面的函数还可以用
除了共有(public)和私有(private),还有保护(protected),在现阶段它和私有差不多也是类外不能访问
讲封装我们先讲讲c语言是怎么样的,C语言数据和方法是分离的
代码,栈的代码,没写全部,只写个架子,主要是为了理解为什么c语言的不好用
//C -- 数据和方法是分离的
//太自由
struct Stack
{
int* _a;
int _top;
int _capacity;
};
void StackInit(struct Stack* ps)
{
ps->_a = NULL;
ps->_top = 0; // ps->_top = -1;
ps->_capacity = 0;
}
void StackPush(struct Stack* ps, int x)
{}
int StackTop(struct Stack* ps)
{}
int main()
{
struct Stack st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
printf("%dn", StackTop(&st));
printf("%dn", st._a[st._top]); // 可能就存在误用
printf("%dn", st._a[st._top-1]); // 可能就存在误用
return 0;
}
这里其实就是有的人可能用代码不规范,直接访问top,但是作为这个栈代码,不是你自己写的,那么你那种调用就有可能误用,因为你不知道你栈顶是首位还是首位的后一位
c语言太过自由,约束太少,毕竟不同的人有不同的习惯,所以代码的使用也是因人而异
而c++就用了类,把成员和函数连接在一起,强行让使用代码的人,代码规范化
代码
// 封装:更严格管理设计
// 1、数据和方法封装到一起,类里面
// 2、想给你自由访问的设计成共有,不想给你直接访问的设计成私有
// 一般情况设计类,成员数据都是私有或者保护,想给访问的函数是共有,不想给你访问时私有或保护
class Stack
{
private:
void Checkcapaicty()
{}
public:
void Init()
{}
void Push(int x)
{}
int Top()
{}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
cout << st.Top() << endl;
//cout << st._a[st._top] << endl;
return 0;
}
比如这样,让不能用的私有化,能用的公有化,函数的调用也限制掉,比如之前的cout << st._a[st._top] << endl;如果和c语言一样调用的话,编译器会编译不过去
5.类的作用域代码
class stack
{
public:
void Init();
};
class Queue
{
public:
void Init();
};
这二个为什么能同名,这是不是重载,重载是要求同一个作用域,而不同作用类域同名也可以同时存在
c语言一个函数分成一个又一个的文件
那么c++是怎么实现头文件和主函数的
头文件
class Stack
{
public:
// 在类里面定义
// 在类里面定义的函数默认是inline
void Init()
{
_a = nullptr;
_top = 0;
_capacity = 0;
}
// 在类里面声明
void Push(int x);
void Pop();
// 总结一下:实际中,一般情况下,短小函数可以直接在类里面定义,长一点函数声明和定义分离
private:
int* _a;
int _top;
int _capacity;
};
栈函数
#include "Stack.h"
// ʵ
void Stack::Push(int x)
{
// ...
_top++;
}
void Stack::Pop()
{
}
这里为什么能访问成员,因为私有限制的是类外的,在类里面是不限制的
,比如房子,房产证的名字是你的,这是不是只属于你私有的房子,那么对于它的主人,你是不是有权限改变先东西,而指定域,Stack:的意思就是进入类域
这里有个问题下面代码是声明还是定义
这个是上面代码截一下部分下来的
//private: int* _a; int _top; int _capacity;
看是声明还是定义,其实就看他有没有开辟空间,没开辟就是声明,开辟了就是定义,所以这个是声明,定义是在Stack st;这串代码里
6.类的实例化用类类型创建对象的过程,称为类的实例化
- 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
class Stack
{
private:
void Checkcapaicty()
{}
public:
void Init()
{}
void Push(int x)
{}
int Top()
{}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack st;
cout << sizeof(st) << endl;
//cout << st._a[st._top] << endl;
return 0;
}
这里打印的是12,像那些函数没算上去
代码 下面st1和st2一样吗?调用是的同一个函数吗?
int main()
{
Stack st1;
st1._top;
st1.Init();
Stack st2;
st2._top;
st2.Init();
}
从汇编看到是调用的同一函数
但是他们的不一样的,可能st1的top是5,st2的top是10,他们分别在公共代码段里存储着不用的值
代码,求A1打印结果
class A1 {
public:
void f1() {}
private:
int _a;
char _c;
};
int main()
{
cout << sizeof(A1) << endl;
return 0;
}
结果
这个简单,int四个字节char一个字节又因为最大对齐数是int所以要求被四整除,所以自动对齐到8
代码 一样 求A2和A3打印结果
class A1 {
public:
void f1() {}
private:
int _a;
char _c;
};
class A2 {
public:
void f2() {}
};
class A3
{};
int main()
{
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
return 0;
}
结果
为什么会有1字节,这A2和A3这个1不是为了存有效数据而是为了占位置,表示对象存在
但是如果这样的话
代码
class A3
{
char _c;
};
这样就是用来存有效数据char了
2.隐含的this指针代码
class Date
{
public:
void printf()
{
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(2022, 5, 14);
d2.SetDate(2022, 5, 13);
d1.printf();
d2.printf();
return 0;
}
根据我们上面得到的这二个调用的是同一个函数,但是它们存的数据不同,分别放在公共代码区,那么它们是用什么区别的?
这里就要讲到this指针了
它们被编译器处理了变成什么样呢?
图片
它们会从图片上部分被编译器处理变成图片下半部分的样子,这样子就可以完全看懂了,它们调用了同一个函数,但是它们传的形参不是相同的



