[C++] 类与对象(上)

这篇具有很好参考价值的文章主要介绍了[C++] 类与对象(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[C++] 类与对象(上),C++,c++,开发语言 

目录

1、前言

2、类的引入

3、类的定义

3.1 类的两种定义方式

4、类的访问限定符

5、类的作用域

6、类的实例化

7、类对象模型

7.1 内存对齐规则

7.1 类对象的存储方式

8、this指针

8.1 this指针的特性

8.2 this指针是否可以为空


1、前言

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

我们来举列子说明一下:

比如蒸米饭这件事,C语言关注的就是,淘米 -> 加水 -> 加米 -> 起锅 -> 烧锅 -> 水沸腾 -> 放入盛有生米的盆 -> 烧锅 -> 拿出;C++在这里关注的是对象:人、米、水、电饭煲,人不需要知道电饭煲如果工作的,只需要四个对象之间交互完成任务就可以。

2、类的引入

C语言结构体(struct)中只能定义变量。

而在C++中,新增加了玩法,结构体内不仅可以定义变量,也可以定义函数

举例:

struct Person
{
	void personInit()
	{
		cout << "void personInit()" << endl;
	}

	int _age;
	char _name[20];
};
int main()
{
	Person p;
	p.personInit();

	return 0;
}

上面结构体的定义,在C++中更喜欢用class来代替。

3、类的定义

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

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省略。
类体中内容称为类的成员:类中的变量称为类的属性成员变量; 类中的函数称为类的方法或者成员函数

3.1 类的两种定义方式

3.1.1 声明和定义全部放在类体中

需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

class Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

private:
	int _age;
	char _name[20];
};

3.1.2 类声明放在.h文件中,成员函数定义放在.cpp文件中
注意:成员函数名前需要加类名::

//Person.h
class Person
{
public:
	void PersonInit();

private:
	int _age;
	char _name[20];
};


//Person.c
#include "Person.h"
void Person::PersonInit()
{
	cout << "void Person::PersonInit()" << endl;
}

一般情况下,更期望采用第二种方式。

注意:一般在声明成员变量的时候成员变量前加_(下划线),为区分成员函数的形参(只要能区分就可以,前家下划线是我的一种方式,谷歌C++规范一般喜欢后加_)。

如果成员变量没有特殊标记时,当在成员函数内用到成员变量,并为其赋值的时候,函数会采用局部优先的原理,将自己赋给自己,这样就达不到预期的效果。

4、类的访问限定符

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

[C++] 类与对象(上),C++,c++,开发语言

【访问限定符说明】

1. public修饰的成员在类外可以直接被访问;
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的);
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止;
4. 如果后面没有访问限定符,作用域就到 } 即类结束;
5. class的默认访问权限为private,struct为public(因为struct要兼容C)。

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别。

5、类的作用域

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

class Person
{
public:
	void PersonInit();//声明

private:
	int _age;
	char _name[20];
};


//初始化定义的时候函数名前加 Person::,表明PersonInit是Person类域的
void Person::PersonInit()//定义
{
	cout << "void Person::PersonInit()" << endl;
}

6、类的实例化

用类类型创建对象的过程,称为类的实例化。

在实例化之前,定义出来的类是不占空间的。
例如:

class Person
{
public:
    void PersonInit()
    {
        cout << "void PersonInit()" << endl;
    }

private:
    int _age;		//声明
    char _name[20];
};

int main()
{
	Person::_age = 20;
    //定义开空间
    Person p;

    return 0;
}

在没有实例化p的时候,定义的 class Person 类不会开辟空间。

[C++] 类与对象(上),C++,c++,开发语言

实例化出了 p 对象,这时 p 是占用实际的空间的,存储了成员变量。(这里实例化后,p也不能直接用_age,因为是私有的,后面会讲如何赋值,打印)。

类就像是设计图。

类实例化出对象就像现实中使用设计图盖房子。

在没有盖房子之前,这块区域没有占空间。

实例化就是按图盖房子,这时就占用了空间。

我们可以使用设计图盖多个房子,这些房子都占空间

[C++] 类与对象(上),C++,c++,开发语言

7、类对象模型

如何计算类对象的大小呢?

例如:

class A
{
public:
	void AInit(int a, int b)
	{
		cout << "void AInit(int a, int b)" << endl;
	}

private:
	int _a;
	int _b;
};
class B
{

private:
	int _a;
	int _b;
};
class C
{};
int main()
{
	cout << "类A的大小:" << sizeof(A) << endl;
	cout << "类B的大小:" << sizeof(B) << endl;
	cout << "类C的大小:" << sizeof(C) << endl;

	return 0;
}

运行结果:

[C++] 类与对象(上),C++,c++,开发语言

总结:

1、成员函数不算在类的大小中;

2、类的大小只与成员变量有关,并遵循结构体对齐规则;

3、空类的大小为1字节(不存储数据,只是占位,表示对象存在过)。

7.1 内存对齐规则

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的对齐数为8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

7.1 类对象的存储方式

为什么类中的成员函数不占空间?那成员函数是存在哪里呢?

实例化后的类中只存储类成员变量

成员函数保存在公共的代码段。

我们画图来理解一下:

[C++] 类与对象(上),C++,c++,开发语言

8、this指针

我们这里写一个日期类来看一下:

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;
	d1.Init(2023, 7, 30);

	return 0;
}

这里看似 Init 函数只有三个形参

调用的时候传了三个参数

实际上,这里还隐含了一个 this 指针。

我们这里画图来看一下:

[C++] 类与对象(上),C++,c++,开发语言

这里对成员变量赋值的时候,前后都会加一个 this-> 来接引用访问。

[C++] 类与对象(上),C++,c++,开发语言

8.1 this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在“成员函数”的内部使用。
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

因此,我们写的时候就不可以这样写:

class Date
{
public:
	void Init(Date* this, int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Init(&d1, 2023, 7, 30);

	return 0;
}

[C++] 类与对象(上),C++,c++,开发语言

this指针隐含着,如果我们自己加上就是错误的。

this在实参和形参的位置上不能显示写

但是在类里面可以显示的用

如下:

class Date
{
public:
    //this在实参和形参的位置上不能显示写
    //但是在类里面可以显示的用
	void Init(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, 7, 30);

	return 0;
}

8.2 this指针是否可以为空

我们来看下面几段代码:

class Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();

    return 0;
}

运行结果:

[C++] 类与对象(上),C++,c++,开发语言

这里我们就会产生疑问,p是空指针为什么可以解引用呢?还是正常运行。

这里对于函数定义在类里面且短小,编译器会当作内联函数,直接展开,并不会解引用;

而如果声明与定义分离或者编译器不将其当作内联函数,就是call Init函数(调用函数)的地址,也不是解引用。

我们继续看:

class Person
{
public:
	void PersonInit()
	{
		cout << "void PersonInit()" << endl;
	}

//private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();
	p->_age = 1;

	return 0;
}

这就会导致运行崩溃,对空指针的内容进行解引用。

[C++] 类与对象(上),C++,c++,开发语言

我们接着上面看:

class Person
{
public:
	void PersonInit()
	{
		cout << _age << endl;
	}

//private:
	int _age;		//声明
	char _name[20];
};

int main()
{
	Person* p = nullptr; //初始化为空指针
	p->PersonInit();

	return 0;
}

这里在调用Init函数的时候,函数里面产生了解引用,但是this是空指针,这里就会运行崩溃。

[C++] 类与对象(上),C++,c++,开发语言

空指针不会编译错误,只会导致运行崩溃。文章来源地址https://www.toymoban.com/news/detail-618367.html

到了这里,关于[C++] 类与对象(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript类与对象:面向对象编程的基础

    TypeScript 是 JavaScript 的一个超集,它为 JavaScript 添加了静态类型、类、接口和装饰器等面向对象编程的特性,并通过编译器将 TypeScript 编译成JavaScript,可以在任何 JavaScript 环境中运行,因此成为了 JavaScript 开发中不可或缺的工具。面向对象编程是现代编程语言的基础,而 Ty

    2024年02月09日
    浏览(46)
  • 对象之舞:Java类与对象的探索

    对象是类的一个实例,可以有属性和方法。属性是对象的特征,方法是对象的行为。 类是对象的抽象,描述了具有共同属性和行为的一组对象。 封装是将属性和方法封装在类中,不允许外部直接访问和修改对象的属性,只能通过类的方法进行操作。封装可以提高代码的安全

    2024年02月15日
    浏览(48)
  • 【C++】——类与对象(中)+日期类对象的实现

    今天我们来继续学习C++类与对象(中)的相关知识点。 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认

    2024年02月04日
    浏览(41)
  • PHP类与对象 (基础)

    在 面向对象编程(Object-Oriented Programming,简称OOP) 中,类和对象是两个关键概念。 类是一种抽象的数据类型,用于定义对象的属性和行为。 对象是类的具体实例,具有类所定义的属性和行为。 类的概念以及特点 类是一种模板或蓝图,用于定义对象的共同属性和行为。它是

    2024年02月15日
    浏览(40)
  • 【C++】类与对象(上)

    之前的文章中讲解了,什么是类、类的实例化,以及封装的意义,若仍有不理解的部分可以移步上一篇文章  【C++】类与对象(引入) 目录 系列文章 1.默认成员函数 2.构造函数 2.1定义 2.2特性 2.2.1重载构造函数 2.2.2与缺省参数混合使用 2.2.3默认构造函数 3.析构函数 3.1定义

    2023年04月15日
    浏览(44)
  • 【C++】——类与对象(上)

    今天我们来学习C++初期最重要的知识点,类与对象,因为类与对象涉及的知识太多,所以我将分为上中下三个部分来为大家讲解类与对象。 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 C++是基于面向对象的,关注的是对象,将一

    2024年02月02日
    浏览(41)
  • C++:类与对象

    类是对一组具有共同属性特征和行为特征的对象的抽象,它可将相关数据和这些数据的操作(函数)组合在一起。 类定义格式: 类名 : class是声明类的,类名是标识符,且在其作用域内必须是唯一的。 注:C++规定,标识符以字母(大小写均可,但区分大小写)或下划

    2024年02月12日
    浏览(44)
  • 【python】类与对象

    类:对一系列变量与方法的封装 创建一个类需要使用 class,例如创建一个学生类,其中要包含学生的姓名、学号、性别、年龄四个信息: 创建一个类对象也就是对类实现实例化: 在类内部定义的变量成为类的成员变量,类内定义的函数方法称为类的成员方法 我们可以

    2024年02月12日
    浏览(31)
  • [C++] 类与对象(上)

      目录 1、前言 2、类的引入 3、类的定义 3.1 类的两种定义方式 4、类的访问限定符 5、类的作用域 6、类的实例化 7、类对象模型 7.1 内存对齐规则 7.1 类对象的存储方式 8、this指针 8.1 this指针的特性 8.2 this指针是否可以为空 C语言是 面向过程 的, 关注 的是 过程 ,分析出求解

    2024年02月15日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包