类和对象 上

目录

引入类class

例1

 例2

构造函数

特征

1.函数名和类名相同

2.无返回值

3.对象实例化时编译器自动调用对应的构造函数

4.可重载

5.构造函数是为了初始化的,但是它只初始化自定义类型,对内置类型不初始化

实例化

析构函数

概念

特征

1.在类名前加上字符 ~

2.无参数无返回值

3.只能有一个析构函数,没有编译器自己生成一个

拷贝构造

特征

1.拷贝构造是也是构造函数

2.拷贝构造参数必须传引用(为什么)

传值传参(语法限制)

 传引用传参

 传指针传参 (普通的构造函数)


引入类class

例1

#include <iostream>
using namespace std;
class Date
{
public:
    //成员函数
	void Init(int year = 2023, int month = 1, int day = 28)//定义
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void func()
	{

	}
    //成员变量
private:
	int _year;//声明
	int _month;
	int _day;
};
int main()
{
	Date* ptr = nullptr;

	ptr->func();
	(*ptr).func();
	ptr->Init(2022,1,28);

	return 0;
}

引入成员函数和成员变量

运行结果是第三个跑不了

前两个汇编代码一样

成员函数在代码段上,这里创建出来的对象的大小是12Bit(如果成员变量没有,默认大小是1Bit)

我自己的理解:ptr是一个Date类型的指针,具有获得Date类型信息的能力,虽然是一个空指针,但是不影响调用代码段里这个类域里的public成员函数,那么为什么(*ptr)这里不会解引用呢?

看下汇编,编译器实际上什么也没干,我觉得它就是获得一个类,到这个类域里面去找成员函数,如果是成员函数 ,那么就在代码段里,但如果是成员变量,栈里没有就会报错,可以说是找不到对应的左值


 例2

这里有个问题,下面的_year来自哪里

void Init(int year = 2023, int month = 1, int day = 28)
{
	_year = year;
	_month = month;
	_day = day;
}

和c是大差不差,也是是要传,不然怎么赋值,但是c++的类,编译器自己传了 Date* this

也就是编译器简化了我们的操作

前面可以写成是  this->_year = year;

实际操作应该如下:

int main()
{
	Date d1;
	d1.Init(2024, 1, 28);
	//d1.Init(&d1, 2024, 1, 28);
	return 0;
}

构造函数

#include <iostream>
using namespace std;
class Date
{
public:
	//不写  编译器自己生成的也是默认构造
	//只能有一个默认构造函数
	//Date()//默认构造函数
	//{

	//}
	//Date(Date* this, int year = 2023, int month = 1, int day = 28)
	//定义
	Date(int year = 2023, int month = 1, int day = 28)//全缺省也是默认构造 Date*this
	{
		
		this->_year = year;

		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;//声明
	int _month;
	int _day;
};

注意:构造函数不是开空间创建对象,而是初始化对象

特征

1.函数名和类名相同

2.无返回值

3.对象实例化时编译器自动调对应的构造函数

4.可重载

默认构造函数有3个,

1.不写时编译器自己生成

2.无参的构造函数

3.全缺省的构造函数

但是只能存在一个

其实非常简单,默认可以理解成不能传参数的构造函数,构造函数又可以重载,如果有多个无参的编译器不知道调哪一个

5.构造函数是为了初始化的,但是它只初始化自定义类型,对内置类型不初始化

我是这么理解的:自定义类型也是由多个内置类型组成的,(这个自定义类型有构造)

只不过在你新的类的成员变量里的自定义类型,调用的也是写过的东西(java里叫组成)

简单来说,为什么只初始化自定义类型,因为你写过了,不是说你不用写,如果你不写,对应的内置类型就是随机值,针对这个问题,C++11打了补丁,引入成员变量的缺省参数

顺序是先执行默认构造,在执行成员变量的缺省参数( 资料:成员变量的缺省参数(即初始化器)会在默认构造函数中执行,而不是在对象创建时另外执行。

实例化

来个有意思的

int main()
{
	Date d1;
	Date d2();
	return 0;
}

发现编译器d2这一行居然不报错,但是实际上编译器没有任何操作

这行代码没有对应的指令

你看 Date(类型)  d2 (函数名/对象) 最后的()是 无参数

编译器不知道是声明函数还是实例化对象,语法上可以,调用时有歧义


析构函数

概念

对象销毁时会自动调用,主要是为了释放开辟的堆空间,同一块区域析构两次会运行崩溃

特征

1.在类名前加上字符 ~

2.无参数无返回值

3.只能有一个析构函数,没有编译器自己生成一个

~Date()
{
    print();
}

就像这样 print()证明调用过,有malloc的free就行


拷贝构造

特征

1.拷贝构造是也是构造函数

2.拷贝构造参数必须传引用(为什么)

Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

什么时候要调用拷贝构造?用一个Date类型去初始化另一个Date类型时候

int main()
{
	Date d1;
	Date d2(d1);
	Date d3 = d1;
	
	return 0;
}

在C++里一共有3中传参方式,,,

传值传参(语法限制)
Date(const Date d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
 传引用传参
Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

 为什么一定要传引用传参?

首先,你不写,编译器是会自己生成一个拷贝构造,这个拷贝构造是浅拷贝(值拷贝),只是单纯的赋值,如果说是这样:

Stack st1;
Stack st2(st1);

 那么他们指针会指向用一个地方,很明显全乱套了(在这种有指针的情况下)

之前说的:用一个Date类型去初始化另一个Date类型时候会调用拷贝构造

那么如果是传值传参,他就会去调用拷贝构造(这里就好比是Date d(d1)  ),好   现在去调用拷贝构造,但是这个拷贝构造里的参数  是一个传值传参,他又要去调拷贝构造,所以无穷递归

 传指针传参 (普通的构造函数)
Date(const Date* d)
{
	this->_year = d->_year;
	this->_month = d->_month;
	this->_day = d->_day;
}

调用时要多加&(取地址)

Date d1;
Date d2(&d1);
Date d3 = &d1;

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值