C++——类和对象入门

类的引入

结构体

我们在C语言定义链表时,经常会写如下代码

但是我们在C++里,发现不用加struct也可以定义新变量

这是因为,在C++中结构体已经被优化成了类,而这个ListNode便被称为类名

在C++里,我们把所有的结构体优化成了类,在类中不仅可以定义成员变量,还可以定义成员函数,对于结构体的定义,我们更喜欢用class来表示

 此刻,我们便开始接触到了C++的灵魂:面向对象

类的定义

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

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分
号不能省略。

类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者
成员函数。

类的定义规则

类的定义方式一般分为以下两种:

  1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内
    联函数处理。
  2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名:: 

第一种:全部放在类体中

 第二种:声明在头文件,定义在源文件

 

一般来说,在工程里我们一般使用第二种方式。

成员定义规则

我们来看以下场景:
 

class date
{
public:
	void print()
	{
		cout << year << "/" << month << '/' << day << endl;
	}

	void Date(int year=1900, int month=1, int day=1)
	{
		year = year;
		month = month;
		day = day;
	}
private:
	int year;
	int month;
	int day;
};
int main()
{
	date a;
	a.Date(2023, 7, 31);
	a.print();
}

 我们在类中的Data函数完成了类的初赋值,当我们运行该程序,我们认为的结果应该是赋值了2023年7月31日,但是实际的结果是

 为什么?

我们再来仔细读一下程序

我们发现,在类中定义的变量和传入的参数名是相同的,编译器对year=year的赋值是传入的参数名对自身的赋值,而不是对类中的变量进行赋值

(关于为什么不是对类中变量进行赋值,在后面this指针会有详细讲解)

所以,我们要尽量将变量名称区分开,在工程里我们一般将类中名称前加上"_"

class date
{
public:
	void print()
	{
		cout << _year << "/" << _month << '/' << _day << endl;
	}

	void Date(int year=1900, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	date a;
	a.Date(2023, 7, 31);
	a.print();
}

此时,程序的运行便正常了

类的访问限定符

访问限定符由来

我们在C语言里定义栈时,top的初取值不同会导致函数的不同,而其实现的结果是一样的。我们在取栈顶元素的函数里根据个人习惯会取不同的top值,但是,有些人可能会为了方便不使用取栈顶元素函数,而是直接访问a[top],最终取到一个随机值

C语言解析栈和队列

此刻,为了避免某些自以为是的人导致程序崩溃,C++定义类可以让他们无法取到top的值

 访问限定符

在C语言中,有3个访问限定符:

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

其中,public表示外部可以访问的成员,而protected和private表示外部不可访问的成员(在此处其作用类似) ,一个访问限定符的作用域在下一个访问限定符或类定义终止时结束

struct和class的区别

C++为了可以兼容C语言,struct便沿袭了C语言的习惯,所有成员都可以直接访问(即默认均为public),而class则是默认均为private

只有class的成员不可访问

类的作用域

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

第一个_a无法识别,第二个_a可以识别

类的实例化

用类类型创建对象的过程,称为类的实例化
类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没
有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个
类,来描述具体学生信息。
 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量

做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设
计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象
才能实际存储数据,占用物理空间

 

只有实例化后才可以调用成员函数

 类的存储方式

比如以下这一个类,与C语言不同的是既有成员函数又有成员变量,我们应该如何计算类的大小呢?

1.普通情况

 我们运行后发现,整个类A只有4个字节,即只占用了int的存储空间,我们不难推断出,类中的成员函数是不占用空间的,因为如果每创建一次新变量便创建一次成员函数,其空间消耗会大大提升

就好比类是一个小区,定义一个新变量后相当于为这一个变量搭建了一栋楼房,而成员函数就是小区的公共区域,不会为每一个类二次搭建.

2.内存对齐

类同样和结构体遵循内存对齐的规则

 具体规则可以去看结构体内存对齐规则,在此不做过多赘述

3.只含有成员函数

 由情况1我们可以知道,在一般情况下,类不会为成员函数开辟空间,而若只有成员函数,我们运行会发现,情况和我们想象并不一样

 这是因为,在没有其他成员变量的情况下,如果没有空间为类占位,我们将无法访问到这个类以及其中的函数,所以这一个字节实际上只是为类进行占位

 

没有成员的类也为一个字节

This指针

 This指针的引入

我们从类的存储方式可以得知,类不会为每一个类变量开辟一个成员函数的空间,每一个变量调用函数时调用的是相同的函数,那么,我们该如何区分调用函数的对象呢?

在编译器中的解决方案是,每一个成员函数的第一个参数都是this指针,在我们调用成员函数时,会先传入这个变量的地址

这个this指针是透明的,即不需要使用者传入,也不需要编写函数的人写入this指针,编译器自动完成,虽然this指针在参数中并没有声明,仍然可以使用这个this指针

这时,我们便可以解决区分不同成员的问题

class date
{
public:
	void print()
	{
		cout << year << "/" << month << '/' << day << endl;
	}

	void Date(int year = 1900, int month = 1, int day = 1)
	{
//通过this指针来访问变量中的成员
		this->year = year;
		this->month = month;
		this->day = day;
	}
private:
	int year;
	int month;
	int day;
};
int main()
{
	date a;
	a.Date(2023, 7, 31);
	a.print();
}

This指针的特性

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

This指针可以是空指针吗

class A
{
public:
	void print()
	{
		cout << "print" << endl;
	}
	void printA()
	{
		cout << "printA  " << _a << endl;
	}
private:
	int _a = 1;
};

int main()
{
	A* a = nullptr;
	a->print();
	a->printA();
}

我们分别调用print和printA,我们发现,只有printA会运行崩溃,而print程序会正常运行,说明,如果我们不使用this指针中的元素,程序则不会受到影响,而一旦我们访问到了this指针之中的元素,程序便会报错

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在面向对象的编程中,C语言并不直接支持和抽象的概念。引用中提到,final关键字用来修饰方法,表示该方法不能在子中被覆盖。而abstract关键字用来修饰抽象方法,表示该方法必须在子中被实现。然而,在C语言中,没有对应的关键字来实现和抽象的概念。 相反,C语言通过结构体来模拟的概念。结构体是一种用户自定义的数据型,可以包含多个不同型的数据成员。通过结构体,我们可以将相关的数据和功能组合在一起。然而,C语言中的结构体不支持继承和多态等面向对象的特性。 在C语言中,我们可以使用函数指针来模拟抽象和接口的概念。函数指针可以指向不同的函数,通过使用函数指针,我们可以实现多态性,即在运行时根据函数指针指向的具体函数来执行不同的操作。 综上所述,C语言并不直接支持面向对象中的和抽象的概念,但可以使用结构体和函数指针来实现似的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [面向对象——类和对象](https://blog.csdn.net/shouyeren_st/article/details/126210622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [面向对象编程原则(06)——依赖倒转原则](https://blog.csdn.net/lfdfhl/article/details/126673771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值