息壤网站打不开了,中国十大营销策划大师,北京seo排名技术,培训报名前言#xff1a;C语言中的结构体#xff0c;在C有着更高位替代者——类。而类的实例化叫做对象。 本篇文章不定期更新扩展后续内容。 目录 一.面向过程和面向对象初步认识二.类1.C中的结构体2.类的定义类的两种定义方式 3.类的访问限定符及封装访问限定符说明 4.类的实例化对…前言C语言中的结构体在C有着更高位替代者——类。而类的实例化叫做对象。 本篇文章不定期更新扩展后续内容。 目录 一.面向过程和面向对象初步认识二.类1.C中的结构体2.类的定义类的两种定义方式 3.类的访问限定符及封装访问限定符说明 4.类的实例化对象只存储成员变量不存储成员函数成员函数存储在公共代码区 5.this指针 三.六大默认成员函数1.构造函数构造函数特点重点默认构造函数重点初始化列表 2.析构函数析构函数特点 一.面向过程和面向对象初步认识
在学习C语言的时候我就时常听说过面向过程和面向对象但是对这两个概念的认知非常模糊那么这两者有什么区别呢 C语言是面向过程的关注的是过程分析出求解问题的步骤通过函数调用逐步解决问题。 而C是基于面向对象的关注的是对象将一件事情拆分成不同的对象靠对象之间的交互完成。我们不需要关注过程是怎么完成的我们只需要关注对象间的交互。 面向对象有3大特性——封装继承多态。 二.类
1.C中的结构体
C语言中结构体中只能定义变量而在C中结构体中不仅能定义变量还可以定义函数struct升级成了类。 以数据结构——栈为例 直接在结构体内定义函数。 实例化对象时无需再写struct只需写结构体名。 #includeiostream
using namespace std;
typedef struct Stack {int* a;int capacity;int top;void Init() //定义函数{a nullptr;capacity 0;top 0;}
}ST;
int main()
{Stack s1; // 无structs1.Init();return 0;
}2.类的定义 在C中类更喜欢用class而非struct。 这两者在默认访问限定上有些区别struct默认为public而class默认为private更符合面向对象的要求。这也是为什么更喜欢使用class。该点在下文默认访问限定符也会讲解。 class Classname
{//类体成员函数成员变量}; //跟结构体一样有分号不要忘class为定义类的关键字Classname为类名{}中为类的主体类体中的内容称为类的成员类中的变量称为类的属性或成员变量类中的函数称为类的方法或成员函数。 类的两种定义方式 一种就是向上面的栈一样将函数声明定义都写在类里面值得一提的是这种函数会被编译器当成内联函数。 还有一种就是将类声明放在头文件中在源文件中定义函数但是需要注意的是成员函数名前需要加类名::域作用限定符一般第二种用的更多。 //obj.h
#includeiostream
using namespace std;typedef struct Stack {int* a;int capacity;int top;void Init();
}ST;//test.cpp
#includeobj.h
void Stack::Init() // 类名::
{a nullptr;capacity top 0;
}
3.类的访问限定符及封装
C实现封装的方式用类将对象的属性(成员变量)和方法(成员函数)结合在一起让对象更加完善通过访问限定符选择性的将其接口提供给外部的用户使用。 共有3种访问限定符在诸如phpjava等语言中都有。 访问限定符说明 利用好访问限定符可以有效保护好类中的数据防止其他人随便访问。 1.public:公有的类成员可以在任何地方被访问。 protect受保护的类成员则可以被其自身以及其子类和父类访问。 private私有的类成员则只能被其定义所在的类访问。 在学继承之前protect和private使用起来没差 2.struct默认为publicclass默认为private。 3.访问权限作用域从该访问限定符开始到下一个访问限定符出现。 4.如果后面没有访问限定符作用域到 } 为止。 5.一般情况下成员变量都设置为private。 以日期类为例
class Date {
public:void Init(int year, int month, int day){_year year;_month month;_day day;}
private:int _year; //声明没有定义不占空间int _month;int _day;
};4.类的实例化 用类创建对象的过程叫做类的实例化。 1.类是对对象进行描述的是一个模型一样的东西限定了类有哪些成员定义出一个类并没有分配实际的内存空间来存储它。 2.一个类可以实例化出多个对象。实例化出的对象才占用实际的内存空间且只存储成员变量不存储成员函数。 以日期类为例
class Date {
public:void Init(int year, int month, int day){_year year;_month month;_day day;}
private:int _year; //声明没有定义不占空间int _month;int _day;
};int main()
{Date d1; // 类的实例化Date d2, d3; // 一个类可以实例化出多个对象//下面两行代码可行吗为什么//Date::_year 1; //并没有实例化对象只是声明没有开空间更不必说初始化了。//d1._year 1; //实例化了呢也不行因为_year是私有成员变量只能在Date类中更改。return 0;
}对象只存储成员变量不存储成员函数 上文说过类的主体有两个成员变量和成员函数。 但实际上实例化的对象中只存储成员变量而成员函数存储在公共代码区。 请看下例代码类的空间大小计算和结构体一样遵循结构体内存对齐规则
class Date {
public:void Init(int year, int month, int day){_year year;_month month;_day day;}
private:int _year; //声明没有定义不占空间int _month;int _day;
};int main()
{Date s1;cout sizeof(Date) endl;cout sizeof(s1) endl;return 0;
}控制台输出如下 可以发现12是只计算成员变量得到的结果因此可以得知对象中并不存储成员函数。 之所以这样是因为成员函数对每个对象都是一样的其会被存储在公共代码区这样不必要在每次实例化对象时都存储一次成员函数大大提高了程序效率。 成员函数存储在公共代码区 请看如下代码各位觉得能够运行成功吗 class Example
{
public:void Print(){cout Print() endl;}
private:int _a;int _b;
};
int main()
{Example* s1 nullptr;s1-Print(); //空指针指向return 0;
}控制台显示如下 运行成功了为什么呢上面不是空指针解引用问题吗程序应该崩溃呀 答上面说过成员函数存储在公共代码区直接向公共代码区call该函数的地址不需要向对象s1中找东西因此不会发生空指针解引用操作。 5.this指针 类的成员函数中都隐藏了一个this指针参数。 this在实参和形参位置不能显示写但是可以在类里面显示的用。 this指针不可被更改. this指针可以为空就是上面成员函数存在公共代码区的例子。 this指针存在栈帧里面。不要误以为this存在对象中this就是一个形参跟普通形参一样存在栈帧里面。 仍以日期类为例
class Date {
public://this在实参和形参中不能显示地写//在类中可以显示地用(没什么价值)void Init(int year, int month, int day){_year year;_month month;_day day;}/*void Init(Date* const this ,int year, int month, int day){this-_year year;this-_month month;this-_day day;}*/
private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Init(2023, 8, 11); //d1.Init(d1,2023,8,11);return 0;
}三.六大默认成员函数 C中有六个默认成员函数我们不写的话它们会自动生成。 1.构造函数
构造函数最便捷的地方就是自动调用可以在我们忘了初始化的时候发挥作用。 构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任务并不是开空间创建对象而是初始化对象。 其特征如下 1.函数名和类名相同。 2.无返回值不需要写void。 3.对象实例化时编译器自动调用对应的构造函数。 4.构造函数可以重载。可以写多个构造函数提供多种初始化方式 class Date {
public://构造函数函数名和类名相同。Date(int year 1, int month 1, int day 1) //全缺省参数{cout Date() endl; // 借此观察构造函数是否被调用_year year;_month month;_day day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2023,8,11); // 对象实例化时自动调用构造函数一定记住 实参可以任意更改//在对象d1后面接实参是构造函数的特殊的初始化规则。 //Date d2(); //不可以在对象后加括号而不给实参因为编译器分不清你是在创建对象还是调用函数。return 0;
}控制台输出如下可以看到我们并没有调用Date函数Date函数在对象实例化时自动调用了。 构造函数特点重点 构造函数是默认成员函数之一我们不写编译器也会自动生成。 编译生成的默认构造函数的特点 1.我们写了就不会自动生成了我们不写编译器会自动生成一个无参的默认构造函数。 2.内置类型不会处理C11支持声明时给缺省值但是有了缺省值就会处理 3.自定义类型的成员才会处理会去调用这个成员的默认构造函数。注意是默认构造函数而非是构造函数 内置类型就是诸如intdouble这种语言提供的类型而自定义类型就是我们自己定义的类型比如上文的Date。 需要注意的是int* 是内置类型Date* 也是内置类型。只要是指针就是内置类型 默认构造函数重点
ps这个地方刚开始学的时候理解起来挺难的我被绕的晕头转向的。还是要多学多看代码啊。 无参的构造函数和全缺省的构造函数此两者都是我们自己写的都被称为默认构造函数并且默认构造函数只能有一个。 共有3种默认构造函数 1.无参的构造函数 2.全缺省的构造函数 3.我们没写编译器自动生成的构造函数。 总结这3种默认构造函数有一个共同点就是不传参就可以调用。 多个默认构造函数同时存在会有歧义。 如下图所示编译器就会显示无默认构造函数。 而将Date写成全缺省就可以正常运行对应上文的全缺省的构造函数是默认构造函数 初始化列表
2.析构函数 析构函数与构造函数的作用相反析构函数不是完成对对象本身的销毁局部对象的销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作mallocrealloc出来的空间等。 析构函数的特性 1.析构函数名是在类名前加上字符~ 2.无参数无返回值 3.一个类只能有一个析构函数。若未显示定义我们没写系统会自动生成默认的析构函数。注意析构函数不能重载。 4.对象声明周期结束时C编译系统自动给调用析构函数。 5.后定义的对象先析构栈帧。 析构函数特点 跟构造函数类似析构函数具有以下特点 1.我们写了就不会自动生成了我们不写编译器会自动生成一个析构函数。 2.内置类型成员不会处理。 3.自定义类型成员会调用这个成员的析构函数。 ·总结一般情况下都需要我们自己写构造函数决定初始化方式。而成员变量全是自定义类型时可以考虑不写构造函数。
文末BB对哪里有问题的朋友尽管在评论区留言若哪里写的有问题也欢迎朋友们在评论区指出博主看到后会第一时间确定修改。最后制作不易如果对朋友们有帮助的话,希望能给博主点点赞和关注.