C++ 类和对象篇(一) 类的引入

目录

一、类的概念

二、类的引入

三、类的定义 

1.定义一个类

2.struct 和 class 的区别

3.类中成员函数的声明、实现分离

四、封装及类的访问限定符

1.封装

2.类的访问限定符       

五、类的作用域和生命周期

扫描二维码关注公众号,回复: 16373392 查看本文章

六、类的实例化

【概念】

1.隐式创建

2.显式创建

3.显式new创建

七、类和对象的存储方法

1.成员函数存储方法猜想

2.类内成员在内存中的分布  

3.类在内存中的存储位置

4.对象在内存中的存储位置

3.1 全局对象

3.2 局部对象

3.3 静态局部对象

3.4 动态对象

【代码演示】 

 【内存布局】

八、计算类的大小


一、类的概念

1.是什么?

        是对有相同属性和行为的事物的抽象。


2.为什么?

        把有关联的数据和函数放在一起方便管理,且类是面向对象编程的前提。


3.怎么用?

        把要描述的事物的属性和行为(用函数实现)放在一起形成一个类。


二、类的引入

1.struct升级为类        

        在C++中 struct 不但兼容C语言中结构体的语法,而且 struct 在C++中升级成了类。


2.类中能定义函数
        类包含两个部分成员变量、成员函数。所以在C++中,结构体内不仅可以定义变量,也可以定义函数。


3.class也能定义类

        除struct外,C++中还能使用class来定义类,在C++中更常用class来定义类。

拓:struct 在 C 和 C++ 中的细微区别

1.C中使用typedef重命名结构体在,最后一行之后才生效,结构体中使用结构体名也必须带上struct。


2.C++中甚至不需要使用typedef重命名就可直接在类中使用类名。


三、类的定义 

1.定义一个类

class className //法一
{
 // 类体:由成员函数和成员变量组成
 
}; // 一定要注意后面的分号

struct structName //法二
{
 // 类体:由成员函数和成员变量组成
 
}; // 一定要注意后面的分号
        class(或struct)为定义类的关键字,className(structName)为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
        类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数

2.struct 和 class 的区别

C++中既可以使用struct定义类,也可以使用class定义类,二者的区别在于:
        在不加限定符的情况下,struct默认为公有,class默认为私有。

拓: 类的访问限定符       

3.类中成员函数的声明、实现分离

a. 成员函数的 声明和实现 全部放在类体中,需注意:成员函数如果在类中定义,编译器 可能 会将其当成内联函数处理。

b. 成员函数的声明放在.h文件中,成员函数实现放在.cpp文件中。
(注意:当声明和实现分离时,因为声明在类域中,故定义时 成员函数名前需要加上 类名和域作用限定符(::),才能找到该类。

        

在大型项目中推荐把类中成员函数和普通函数一样,将声明和实现分离,类中成员函数声明和定义分离的意义在于方便阅读代码

拓1、成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

        声明和实现分离后,类的成员函数就不会再被当成内联函数了。(内联函数的声明和实现不能分离,内联函数不会进符号表,链接时靠声明无法找到实现的地址)


拓2、在声明和定义分离时:如果定义时中我们不加类的域名,这时类域中和全局域中就会出现两个同名函数,这是可行的且不构成函数重载。(在不同域中的函数不构成重载)   


四、封装及类的访问限定符

1.封装

1.是什么?

        本质上是对数据的管理:隐藏对象的属性和方法的实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。


2.为什么?

        提高程序的安全性和可维护性(改进的难易程度)。


3.怎么做?

         C++实现封装的方式:用类将属性与方法结合在一块,通过设置访问权限选择性的将其接口提供给外部的用户使用。  

2.类的访问限定符       

public(公有)、private(私有)、protected(保护)


五、类的作用域和生命周期

1.类的作用域

         类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域 


2.类的生命周期

        类的生命周期和存储位置有关,如:全局的类和静态的类存储在静态区,它的生命周期就是整个工程,在函数中的类,生命周期随着这个函数……


六、类的实例化

【概念】

用类创建对象的过程,称为类的实例化。一个类可以实例化出多个对象。


        类不占空间,实例化成对象后才会占用空间,用于存储类成员变量。但是我们也可以通过类计算对象占用的空间大小。

        同理,定义结构体不占空间,定义结构体变量才会占用空间,但是我们也可以使用sizeof结构体名来计算结构体变量占用的空间大小。 

1.隐式创建

由编译器调用默认构造函数,在栈中创建。

class A{};
A a;

2.显式创建

在代码中主动调用构造函数,在栈中创建。

class A{};
A a = A();

3.显式new创建

使用了new关键字,在堆中分配内存创建。

class A{};
A* pa = new A();

new出来的对象必须要用指针接收,并且需要显式delete销毁对象释放内存。


七、类和对象的存储方法

1.成员函数存储方法猜想

成员函数存储方法猜想一:将成员函数的地址和成员变量都存起来

存在问题:调的成员函数都是一样的,所以没必要都每个对象都存一个成员函数的地址


成员函数存储方法猜想二:将成员函数的地址单独存放进一张表中,然后存储时多存一个表的地址

这种方法没有什么问题,但在这里没有被采用。


成员函数存储方法猜想三:只存成员变量,将成员函数统一存放在公共代码区。

这个方案就是成员函数的存储方案,运行时不会在对象中找函数的地址,编译链接时才会根据函数名去公共代码区找到函数的地址。

所以类在遇到如下情况,程序不会崩溃。(因为找成员函数的地址不是在类中找,是去公共代码区找,所以类被实例化为nullptr我们依然能够调用成员函数)

 

2.类内成员在内存中的分布  

1)类内的普通成员变量  ------------   栈
2)类内的静态成员变量  ------------   静态区
3)类内的引用变量  ------------   看引用的变量
4)类内的const变量  ------------   栈 (const修饰只是将变量限定为只读的,本质还是变量,存储位置看变量本身,所以const修饰的局部变量仍在栈上,且能通过指针修改。)

5)类的成员函数  ------------  普通成员函数,静态成员函数都在代码区

3.类在内存中的存储位置

        类不会储存在内存中,类只是一个模板告诉程序,如何创建一个对象、需要多少个字节、以及如何销毁等等。

        类实例化出的对象才会保存中内存中。

4.对象在内存中的存储位置

3.1 全局对象

        全局对象存放在全局(静态)存储区,程序结束后由系统调用析构函数释放。


3.2 局部对象

        局部对象存放在中。其生命在作用域结束时结束,它的析构函数会自动被调用,即对象自动被清理。


3.3 静态局部对象

        静态局部对象存放在全局(静态)存储区,其生命在作用域结束之后仍然存在,即此时对象的析构函数并不会被调用,直到整个程序结束。


3.4 动态对象

        动态对象(即new出来的对象)存放在中,其生命在它被 delete 之际结束。用于创建动态对象的指针存放在栈中。
        注:new 的对象,必须使用 delete 去显式的调用析构函数,否则程序不会去调用其析构函数,从而造成内存泄露。


【代码演示】 
class A{
};
class B{
};
class C{
};
class D{
};

A a;  //全局对象
int main(){
	B b;  //局部对象
	static C c;  //静态局部对象
	D *d = new D;  //动态对象
	delete d;
	return 0;
}

 【内存布局】


八、计算类的大小

1.计算成员变量的大小

        类和结构体的一样,也遵守内存对齐规则,从第二个成员变量开始,起始位置要计算,在自己的大小和默认对齐数(VS编译器中默认对齐数为8)中选择较小的那个。最后整个类也必须要对齐:类的大小必须是默认对齐数的整数倍。

        当sizeof计算类的大小的时候会忽略静态成员变量的大小。

2.计算成员函数的大小

        算类的大小时,不用考虑成员函数,故不用加上函数指针的大小。

3.计算空类的大小

        注意,没有成员变量的类(包括空类)的大小为1字节,不存储数据,目的是为了占位,标识对象存在,区分不同的对象。


总结:

        计算类的大小就是按照内存对齐的方式计算类中所有(非静态)成员变量 的大小。

猜你喜欢

转载自blog.csdn.net/look_outs/article/details/129029360
今日推荐