C++笔记(2023.4.19)

目录

宏函数 

内联函数

inline对于编译器仅仅是个建议,最终是否成为inline,取决于编译器,很多情况下会被编译器否决

内联函数不能声明和定义分离,

​编辑

​编辑

关键字auto

关键字nullptr==((void*)0)

 类和对象

类的定义

struct与class两者的区别

三种限定访问符

类的两种定义方式:

面向对象三大特性:封装、继承、多态

类的作用域

类实例化对象/对象定义/对象实例化

类的大小(需要内存对齐)

空类与只有成员函数的类

内存对齐

 This指针(暗箱操作)

const

一个错误认识

C和C++实现栈对比


宏函数 

适用于短小、频繁调用的函数

优点---不需要建立栈帧,提高调用效率

缺点---复杂,容易出错,让可读性变差,不能调试(预处理阶段就发生了替换)

#define   Add(x,y)  ((x)+(y))*10  不用加;分号

记住一定要加括号

内联函数

适用于短小、频繁调用的函数

长函数改成内联会导致代码膨胀;

加个inline;

inline int add(int x,int y)

{

return (x+y)*10;

}

函数如果过长,用inline,会导致可执行程序变大(例安装包变大) 

inline对于编译器仅仅是个建议,最终是否成为inline,取决于编译器,很多情况下会被编译器否决

1、比较长的函数

2、递归函数

3、默认debug模式下,inline不会起作用,不然不方便调试

如下两个程序对比图:

第二个程序没有call调用函数

imul相乘指令

内联函数不能声明和定义分离

分离会存在链接问题,因为没有地址,不会进入符号表,内联和函数直接在用的地方展开

Func.h

#include<iostream>


using namespace std;

inline void f(int i);


test.cpp

int main()
{
	f(10);

	return 0;
}

Func.cpp
void f(int i)
{
	cout << i << endl;
}

Func.h

#include<iostream>


using namespace std;

inline void f(int i)
{


	cout << i << endl;

}


test.cpp
int main()
{

	f(10);

	return 0;
}

关键字auto

自动匹配类型(编译器在编译期间推导而得),使用auto定义变量时,必须对其进行初始化

auto e;(无法通过编译)

int x=10;

auto a=&x;

auto*=&x;//指定类型为指针

auto&=x;

cout<<typeid(a).name<<endl;打印类型

关键字nullptr==((void*)0)

在cpp中,空指针用nullptr表示

cpp中,NULL被替换成了0 

开发语言特点:向前兼容,有问题但也需要留下,不然会导致别人的程序出bug

不用形参时可以不写,int x
接收但不使用,可以仅仅只是为了匹配类型

#include<iostream>

using namespace std;


//不用形参时可以不写,int x
//接收但不使用,可以仅仅只是为了匹配类型

void f(int)

{

cout<<"int"<<endl; 
}

void f(int*)

{

cout<<"int*"<<endl; 

}

int main()

{

f(0);

f(NULL);

f(nullptr);



return 0;

}

 类和对象

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++ 基于面向对象 的, 关注 的是 对象 ,将一件事情拆分成不同的对象,靠对象之间的交互完
成。

外卖系统

面向过程

上架

点餐

派单

送餐

面向对象

商家

骑手

用户

对象和对象之间的关系和交互

类也是一个域,一般C++中有{}就相当于一个域

#include<iostream>

using namespace std;

typedef int DataType;

//类也是一个域,虽然Init函数名相同,但是它们是在不同的域中,一般情况下Cpp有这个{}括号都是一个域
struct Queue {
	void Init()
	{

	}
};

//成员变量可以写在成员函数之后,也可以在之前,因为类域是一个整体
struct Stack
{
	//成员函数  函数名不需要加前缀名称 StackInit
	void Init(size_t capacity=4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}
	void Push(const DataType data)
	{
		// 扩容
		_array[_top] = data;
		++_top;
	}
	DataType Top()
	{
		return _array[_top- 1];
	}
	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_top = 0;
		}
	}

	//成员变量
	DataType* _array;
	size_t _capacity;
	size_t _top;
};

int main()
{
	struct Stack st1;//C

	Stack st2;//C++

	st2.Init();
	st2.Push(1);
	st2.Push(2);
	st2.Push(1);
	st2.Push(2);

	cout << st2.Top() << endl;

	st2.Destroy();
	return 0;
}

类的定义

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

struct与class两者的区别

struct默认为公有;(因为struct要兼容C)

class默认为私有;

三种限定访问符

只要是类都有访问限定符

public(公有);pubilc修饰的成员在类外可以直接被访问

protected(保护);

private(私有);

1. public修饰的成员在类外可以直接被访问

2. protected private 修饰的成员在类外不能直接被访问 ( 此处 protected private 是类似的 )
3. 访问权限 作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class 的默认访问权限为 private struct public( 因为 struct 要兼容 C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

类的两种定义方式:

1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成

联函数处理;

class Stack
{
public:
	//成员函数  函数名不需要加前缀名称 StackInit
	void Init(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}

	void Push(const DataType data)
	{
		// 扩容
		_array[_top] = data;
		++_top;
	}

	DataType Top()
	{
		return _array[_top - 1];
	}

	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_top = 0;
		}
	}

private:
	//成员变量
	DataType* _array;
	size_t _capacity;
	size_t _top;
};

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

Func.h

#include<iostream>

using namespace std;

typedef int DataType;

//struct Stack
class Stack
{
public:
	void Init(size_t capacity = 4);

	void Push(const DataType data);

	DataType Top();

	void Destroy();

private:
	//成员变量
	DataType* _array;
	size_t _capacity;
	size_t _top;
};

Func.cpp

#include"Func.h"

void Stack::Init(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}

void Stack::Push(const DataType data)
{
	// 扩容
	_array[_top] = data;
	++_top;
}

DataType Stack::Top()
{
	return _array[_top - 1];
}

void Stack::Destroy()
{
	if (_array)
	{
		free(_array);
		_array = nullptr;
		_capacity = 0;
		_top = 0;
	}
}

一般前加_或后加_或尾加个m表示为成员变量

成员变量命名规则的建议:
// 我们看看这个函数,是不是很僵硬?
class Date
{
public:
 void Init(int year)
 {
 // 这里的year到底是成员变量,还是函数形参?
 year = year;
 }
private:
 int year;
};
// 所以一般都建议这样
class Date
{
public:
 void Init(int year)
 {
 _year = year;
 }
private:
 int _year;
};
// 或者这样
class Date
{
public:
 void Init(int year)
 {
 mYear = year;
 }
private:
 int mYear;
}

面向对象三大特性:封装、继承、多态

封装本质上是一种管理,让用户更方便使用类 

局部->类->全局

成员变量不开空间就是声明,定义是整体定义

类的作用域

类定义了一个新的作用域 ,类的所有成员都在类的作用域中 在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域。
局部域和全局域会影响生命周期
类域与命名空间域不会影响生命周期
局部域->类域->全局域
class Person
{
public:
 void PrintPersonInfo();
private:
 char _name[20];
 char _gender[3];
 int  _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
 cout << _name << " "<< _gender << " " << _age << endl;
}

类实例化对象/对象定义/对象实例化

声明和定义的区别在于开不开空间

类里面的成员变量是整体定义的

//int main()
//{
//	// 类实例化对象/对象定义
//	Stack st1;
//	Stack st2;
//	//st1.top = 1;
//
//	// 不能,类访问top是声明,top不能存数据
//	//Stack::top = 1;
//
//	return 0;
//}

类的大小(需要内存对齐)

对象的大小只算成员变量,不算成员函数

成员函数是在公共区域,不然每个对象都存,太浪费了

int main()
{
	// 类实例化对象/对象定义
	Stack st1;
	Stack st2;
	Stack st3;
	Stack st4;

	st1.top = 0;
	st1.Push(1);

	st2.top = 1;
	st2.Push(1);

	// 对象中只存储的成员变量,没有存储成员函数
	cout << sizeof(st1) << endl;

	return 0;
}

空类与只有成员函数的类

没有成员变量的类对象,需要1byte,是为了占位,表示对象存在
  如果字节为0,那么它们连地址都没有,无法定义对象
  不存储有效数据

#include<iostream>

using namespace std;


class A1
{
public:
	//成员函数
	
	//默认构造函数
	A1(int a = 1)
	{
		_a = a;
	}

	void  printf()
	{
		cout <<this->_a << endl;
	}

	//成员变量
private:
	int _a;

};


class A2 {
public:
	void f1() {}
private:
	char _ch;
	//int _a;
	double _d;
};


//类中什么都没有——空类
class B
{

};

// 类中仅有成员函数
class C
{
	void  printf()
	{
		cout << "C" << endl;
	}
};


int main()
{
	//无传参,初始化默认为缺省值
	A1 a1;
	//有传参,初始化为传参值
	A1 a2(2);

	a1.printf();
	a2.printf();

	A2 a21;
	A2 a22;

	//sizeof(对象)和sizeof(类)大小相同
	cout << sizeof(a21) << endl;
	cout << sizeof(a22) << endl;
	cout <<"A2:" <<sizeof(A2) << endl;



	/* 没有成员变量的类对象,需要1byte,是为了占位,表示对象存在
	 如果字节为0,那么它们连地址都没有,无法定义对象
     不存储有效数据*/
	//空类
	cout <<"B:"<< sizeof(B) << endl;

	// 类中仅有成员函数
	cout <<"C:"<< sizeof(C) << endl;

	B b1;
	B b2;
	C c1;
	C c2;
	cout << &b1 << endl;
	cout << &b2 << endl;
	cout << &c1 << endl;
	cout << &c2 << endl;

	return 0;
}

内存对齐

从上面A2的大小,我们来讨论另一个知识点,内存对齐

 

还有一个知识点大小端

 This指针(暗箱操作)

this指针不允许在形参和实参中显示使用,但允许在成员函数里面写

this指针是一个形参,它存在栈区里

 下面我们再来看几种错误写法

看两个代码正确认识this指针

const

Date*const this 无法改this,可以改this里面的内容

Date const*this 和const Date*this  可以改this指向,不可以修改里面的内容

一个错误认识

表达式左边必须为可修改的左值代表其为不可修改的常量

C和C++实现栈对比

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值