C++基础+类和对象上

C++基础部分

一,内联函数

1,用inline修饰的函数叫内联函数,编译时c++编译器会在调用的时候展开内联函数,这样就不需要建立栈帧了,提高效率。

2,inline对编译器只是一个建议,也就是说,编译器可以选择不展开内联函数。inline适用于频繁调用短小的函数。对于递归,代码相对多的一些函数,加上inline编译器会自动忽略掉 。

3,c语言中的宏定义就是在预处理时替换展开,但是宏定义容易出错,所以c++用内联函数来代替宏定义使用。

4,vs编译器的debug版本下,默认是不展开inline的,这样方便调试,debug版本下想展开需要设置一下两个地方。

#include <iostream>
using namespace std;
inline int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = Add(1, 2);
	cout << ret << endl;
}

这段代码运行后转到汇编指令下:

这样就减少了函数栈帧的建立。

5,inline 声明和定义不能分离到两个文件,分离会导致连接错误。因为inline被展开,就没有函数地址,链接时会报错。因为内联函数是直接展开的,默认是没有地址的。

源码

#include "test.h"
#include <iostream>
using namespace std;
int main()
{
    int ret = Add(1, 2);
    cout << ret << endl;
}

test.h声明 

inline int Add(int x, int y);

tpp.h定义

int Add(int x, int y)
{
    return x + y;
}

       总的来说,内联函数就是一种建议,你写了编译器也不一定会用,这个取决于编译器。如果内联函数可以随便用,那么所有函数都可以展开,都不用建立栈帧了。所以写了内联函数,编译器会判断合不合适使用。

二,nullptr

nullptr即为空指针,也就是在c语言中使用的NULL。由于在c++中,NULL被宏定义为0,所以在有些场景下会产生歧义。

 NULL会转化成0,而nullptr不会,它只能转化成指针。所以c++中用nullptr解决这种问题。

//c语言支持,c++不支持

void* p1=NULL;

int* p2=p1;

//c++中

void*p1=nullptr;

int* p2=(int*)p1;

类和对象部分

1,类的定义

1.1类定义的格式


class classname
{
    //由成员函数和成员变量组成
};

(1)class为定义类的关键字,classname为类名, {}中为类的主体。类中的变量称为类的属性或类的成员变量,类中的函数称为类的方法或成员函数

(2)为了区分成员变量,一般在成员变量前加上_,比如_i。

(3)定义在类中的成员函数默认是内联函数。但是是否展开还是取决于编译器。

(4)c++中struct也可以定义类,c++兼容c语言的用法,同时struct升级成了类,与class定义类相比,struct中的成员属性默认是public,而class默认是private.

1.2访问限定符

(1)c++一种实现封装的方式,用类将对象的属性与方法结合起来。通过访问权限,选择性的将其接口提供给外部的用户使用。

(2)public修饰的成员在类外可以直接访问,private和protected修饰的成员在类外不可直接访问。

(3)class没有被访问限定符修饰的默认时private,struct 默认是public.

class stack//定义一个类,类名为stack
{
public://成员函数,类外可直接访问
	void push()
	{}
	void pop()
	{}
	int top()
	{}
private://私有,类外不可直接访问
	int* _a;//成员变量名前加上_,便于区分
	int _top;
	int _capacity;
};
int main()
{
	//与结构体不同的是,类名就是一个类型
	//而在结构体中,需要加上struct才是一个类型
	stack st;//st为定义的对象
	st.push();
	st.pop();//调用成员函数

	//st._top;//不可直接访问
}
1.3类域

类定义了一个新的作用域,类的所用成员都在类的作用域中,在类外定义时,需加上::域作用操作符来指明该变量在哪个域中。

class Date
{
public:
	void Init(int year, int month, int day);
private:
	int _year;
	int _month;
	int _day;
};
void Date::Init(int year, int month, int day)//类外定义
{
	_year = year;
	_month = month;
	_day = day;
}

2,实例化

2.1实例化概念

(1)用类类型在物理内存中创建对象的过程,称作类的实例化。

(2)类实际上只是一个模型,类内成员变量都没有分配空间,只是声明。用类实例化出对象后,才会分配空间。

class Date
{
public:
	void Init(int year, int month, int day)
	{
			_year = year;
			_month = month;
			_day = day;
	}
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	//成员变量的声明
	int _year;
	int _month;
	int _day;
};

int main()
{
	//Date类实例化出对象d1,d2
	Date d1;
	Date d2;

	d1.Init(2024, 7, 25);
	d1.print();

	d2.Init(2024, 7, 15);
	d2.print();

	return 0;
}
2.2对象大小

(1)对象中的存储方式,对象中只存储成员变量,成员函数存放在公共代码区。

(2)计算对象的大小,和结构体一样,都遵循内存对齐规则。 

a.第一个成员在与结构体偏移量为0的地址处。

b.其他成员变量要对齐到某个数字(对齐数)的整数倍地址处。

c.对齐数=编译器默认的对齐数与该成员大小的较小值

d.结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐数取最小)的整数倍。

e.如果嵌套了结构体,嵌套的结构体对其到自己的最大对齐数的整数倍处。

(3)计算Date类的大小

(4)当类中没有成员变量时,对象的大小是1

 2.3this指针

(1)在上面的Date类中,有Init和print两个函数,在我们调用的时候就不知道是要访问d1的数据还是d2的数据,所以这里需要使用c++中隐含的this指针来解决问题。

(2)编译器编译后,在每个成员函数的第一个形参位置,会默认加上一个当前类类型的指针,叫做this指针。

class Date
{
public:
	//void Init(Date* const this,int year, int month, int day)
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
	//void print(Date* const this)
	void print()
	{
		cout << this->_year << "年" << this->_month << "月" << this->_day << "日" << endl;
	}
private:
	//成员变量的声明
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;

	d1.Init(2024, 7, 25);//相当于d1.Init(&d1,2024,7,25)
	d1.print();//相当于d1.print(&d1)

	d2.Init(2024, 7, 15);//d2.Init(&d2,2024, 7, 15)
	d2.print();//d2.print(&d2)

	return 0;
}

注:形参的位置不可出现this指针,但在函数体内可以使用this指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值