首页 > 编程语言 >c++学习

c++学习

时间:2024-12-26 20:27:52浏览次数:7  
标签:p1 int void c++ 学习 Person operate age

这是一份记录一下学习c++的笔记,比较杂乱。
随机数种子
#include
//用时间制作的随机数种子
srand((using int)time(MULL));
rand()%61;//0~60取值
内存分区模型:代码区、全局区
代码区:程序执行前,存放cpu机器指令,共享,只读
全局区:程序执行前,全局变量,静态变量(static),常量(字符串常量,const修饰的全局变量)
栈区:程序执行后,局部变量,形参数据(由编译器开辟,函数执行后自动释放,要注意不能返回局部变量的地址)
堆区:程序执行后,由程序员开辟和释放,new出来的数据返回该数据类型的指针,指针的局部变量放在栈区,数据开辟在堆区存放。注意怎么开辟数组类型new int [10];释放 delete [] arry;
引用
给变量取别名:数据类型 &别名 = 原名
引用要初始化,不可以更改,操作的一直都要是同一块内存
引用传递,实参可以修饰形参与地址传递有一样的效果
不要返回局部变量的引用,返回引用的函数可以作为左值 int& test(); test()=1000;
引用本质是指针常量,值可以改,指向不能改 int * const ref= &a等价与 int& ref = a;
常量引用,const int& a = 10;等价于 int temp = 10; int & a = temp;使用在于修饰形参,防止误修改
函数提高
函数的默认参数:1.参数可以有默认值,但是往后的参数都要有2.函数声明和实现只能有一个有默认值
函数的占位参数:void func(int a;int),也可以有默认值void func(int a;int = 10)
函数的重载:1.作用域相同2.参数的个数,顺序,类型不同3.返回值不能作为条件。引用可以作为重载的条件void test(int &a);void test(const int &a);遇到默认参数如果是void test(int a);和如果是void test(int a,int b=10);调用可能会出现二义性,如果是void test(int a);和void test(const int &a);也会出现二义性。二义性:编译器不知道用哪个函数
12.23今天先到这,明天学一下类和对象--------------------------------------------------------------------------
c++三大特性:封装,继承,多肽
封装:设计类的时候,属性和行为写在一起表现事物。实例化是通过一个类创建具体的对象。属性(成员属性,成员变量)、行为(成员函数,成员方法)
关于权限:public(类内类外都可以访问)protected(类内可以,类外不行,子类可以)private(类内可以,类外不行,子类也不行)
struct的默认权限是public,class的默认权限是private

struct C1
{
	int m_age;//公共权限
};
class C1
{
	int m_age;//私有权限
};

成员属性私有化,可以用方法对其控制读写权限

class Person
{
	private:
		string m_name;
		int m_age;
	public:
		void setName(string name)//通过set方法类外设置
		{
			m_name = name;
		}
		void getName()//通过get方法类外得到
		{
			 return m_name;
		}
};

构造函数和析构函数
特点:没有返回值和类同名,构造函数可重载析构函数不行,会自动调用一次,没有写程序也还会自己增加。析构前加~
构造函数分类:有参和无参(默认构造)、普通和拷贝(拷贝的话要用const 类命 & 变量名)
调用构造函数:
括号法

Person p1;//无参构造
Person p2(10);//有参构造
Person p3(p1);//拷贝构造
//注意无参构造不能加(),会被误会是函数 Person p();是错误的

显示法

Person p1;//无参构造
Person p2 = Person(10);//有参构造
Person p3= Person(p2);//拷贝构造
//匿名对象会马上被回收无法使用 Person(10);
//注意不要用匿名对象调用拷贝构造会被误会重定义 Person(p3) = Person p3;

隐式转换法

Person p1;//无参构造
Person p2 = 10;//有参构造
Person p3= p2;//拷贝构造

拷贝构造函数的调用:
复制已有的对象信息

Person p2(10);
Person p3(p1);//把p2的值都拷贝一份

传值的方式调用

void test(Person p)//拷贝一份
{
}
void copy()
{
	Person p1;
	test(p1);
}

返回值的方式调用

Person test()
{
	Person p1;//局部变量函数结束被销毁
	return p1;//重新拷贝一份
}
void copy()
{
	Person p = test();//p和函数里面的p1地址不一样
}

构造函数的调用规则
默认提供无参构造函数、拷贝构造函数(值拷贝)、析构函数
如果通过有参构造,不提供无参构造只通过拷贝构造;如果通过拷贝构造,有参和无参构造都不提供
深拷贝与浅拷贝
主要是拷贝构造函数的问题,浅拷贝只是简单的值拷贝,如果有指针开辟内存会出现析构重复释放同一个内存地址的问题,要用深拷贝来解决这个问题。深拷贝:在拷贝构造函数里也要重新开辟一个内存

Person(const Person& p)
{
	m_height = new int(*p.m_height);//重新开辟内存,深拷贝
}
~Person()
{
	if(m_height!=NULL)
		delete m_height;//析构函数要释放内存
}

构造函数初始化列表

Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
}

类中有类对象构造和析构的顺序是什么样的,先构造的后析构

class A
{
};
class B
{
	A a;//类中对象先构造,自身的类先析构
};

12.24今天先到封装,明天学一下继承吧!--------------------------------------------------------------------------
静态成员
静态成员变量:所有数据都共享一份内存;编译阶段就分配内存(全局区);类内声明类外初始化,有访问权限。可以通过对象调用,也可以通过类名调用

class Person 
{
	static int m_A;//类内声明
private:
	static int m_B;//私有变量类外无法访问
}
int Person::m_A = 100;//类外初始化
void test01()
{
	Person p;
	p.m_A;//对象调用
	Person::m_A;//类名调用
}

静态成员函数:所有对象都共用一个函数,只能使用静态成员变量(因为非静态成员变量对象不一致,无法在类内使用),有访问权限。可以通过对象调用,也可以通过类名调用

class Person 
{
	static int m_A;//类内声明
	int m_C;
	static void func()
	{
		m_A = 100;//可以修改因为都是一份数据
		m_C = 200;//不可以修改因为对象无法确定
	}
private:
	static void func1();//私有函数类外无法访问	
};
void test01()
{
	Person p;
	p.func();//对象调用
	Person::func();//类名调用
}

成员变量和成员函数分开存储,只有非静态成员变量才是属于类的对象上,空对象占一个字节(区分空对象占内存的位置)

class Person 
{
	int m_A;//非静态成员变量,属于类的对象
	static int m_B;//静态成员变量,不属于类的对象
	void funC();//非静态成员函数,不属于类的对象
	static void funA();//静态成员函数,不属于类的对象
};

this指针的用途:解决命名冲突;返回*this,可以实现链式编程

class Person 
{
	int age;
	void setAge(int age)
	{
		age = age;//形参与成员变量同名,无法进行区分
		this->age = age;//可以解决命名冲突,指向被调用成员函数所属对象
	}
	Person addAge(Person p)//返回值会拷贝一份已经不是本身了
	{
		this->age = p.age;//年龄追加
		return *this;
	}
	Person& addAge(Person p)//返回引用一直都是自己那一份
	{
		this->age = p.age;//年龄追加
		return *this;
	}
};
void test()
{
	Person p1(10);
	Person p2(10);
	p2.addAge(p1).addAge(p1).addAge(p1);//可以实现链式编程
}

注意:this空指针无法访问成员变量

void test()
{
	Person *p = NULL;
	p.getAge();
}
class Person 
{
	int age;
	void getAge()
	{
		if(this==NULL)//指针如果为空无法访问变量,提高健壮性
		{
			return;
		}
		cout<<age;
	}
};

const修饰成员函数:this指针的本质是指针常量,值可以改这种指向不能修改,再再函数本身加上const限定的话称为常函数,值也会不能修改。如果非要修改的话,在变量前加上mutable才可以修改。const修饰对象称为常对象,常对象只能调用常函数限定只读,因为要保持成员变量值也不能修改的特性,常对象中只能修改mutable限定的特殊变量。

class Person 
{
	int age;
	mutable int year;
	void setAge() const//加上const限定 const Person *const this;//指针指向和值都不能修改
	{
		year = 2024;//可以修改,因为有mutable
	}
	void getAge();
};
void test()
{
	const Person p;
	p.getAge();//无法调用,常对象只能调用常函数
	p.setAge();//可以调用常函数
	p.age = 100;//无法修改
	p.year= 100;//可以修改,因为有mutable
}

友元函数:全局函数做友元,类做友元,类内的成员函数做友元,都是加friend,可以访问本类中的私有变量
全局函数

class Bulid 
{
	friend void visit();//告诉编译器这是好朋友可以访问私有变量
	void Bulid()
	{
		m_SettingRoom = "客厅"
		m_BedRoom= "卧室"
	}
public:
	string m_SettingRoom;
private:
	string m_BedRoom;
};
void visit()
{
	Bulid b;
	cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
}

class Bulid 
{
	friend class GoodFriend;//告诉编译器这是好朋友类可以访问私有变量
	void Bulid()
	{
		m_SettingRoom = "客厅"
		m_BedRoom= "卧室"
	}
public:
	string m_SettingRoom;
private:
	string m_BedRoom;
};
class GoodFriend
{
	GoodFriend()
	{
		b = new Bulid;//new出来一个类
	}
	void visit()
	{
		cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
	}
	Bulid b;
};

类的成员函数

class Bulid 
{
	friend void GoodFriend::visit();//告诉编译器这是类下的好朋友函数可以访问私有变量
	void Bulid()
	{
		m_SettingRoom = "客厅"
		m_BedRoom= "卧室"
	}
public:
	string m_SettingRoom;
private:
	string m_BedRoom;
};
class GoodFriend
{
	GoodFriend()
	{
		b = new Bulid;//new出来一个类
	}
	void visit()
	{
		cout<<b.m_SettingRoom <<","<<b.m_BedRoom<<endl;
	}
	Bulid b;
};

运算符重载:operate+(),operate<<(),operate++(),operate++(int),operate=(),operate==(),operate!=(),operate()(),运算符重载可以在类内通过成员函数,也可以通过全局函数。对于已有的数据类型不能随意重载,也不要更改原有的运算规则
operate+()

class Person 
{
	int age;
	Person operate+(Person &p)//通过成员函数重载+,要不要返回引用只是要看要不要对自身数据进行下一步操作
	{
		Person temp;
		temp.age = this->age+p.age;
		return temp;
	}
};
Person operate+(Person &p1,Person &p2)//通过全局函数重载+
{
	Person temp;
	temp.age = p1.age+p2.age;
	return temp;
}
Person operate+(Person &p1,int num)//函数重载的版本
{
	Person temp;
	temp.age = p1.age+num;
	return temp;
}
void test()
{
	Person p1;
	p1.age = 10;
	Person p2;
	p2.age = 10;
	Person p3 = p1+p2;//成员函数本质Person p3 = p1.operate+(p2);
	Person p3 = p1+p2;//全局函数本质Person p3 = operate+(p1,p2);
	Person p3 = p1+10;
}

operate<<(),因为成员函数重载会出现p.operate<<(cout)简化是p<<cout的结构,所以这里使用全局函数重载,输出自定义类型

class Person 
{
	friend ostream& operate<<(ostream &cout,Person &p1);//全局友元可以访问私有变量
private:
	int age;
	Person(int age)
	{
		this->age = age;
	}
	Person operate+(Person &p)//通过成员函数重载+,要不要返回引用只是要看要不要对自身数据进行下一步操作
	{
		Person temp;
		temp.age = this->age+p.age;
		return temp;
	}
};
ostream& operate<<(ostream &cout,Person &p1)//通过全局函数重载+,本质operat<<(cout,p)简化cout<<p
{
	cout<<p1.age;
	return cout;
}
void test()
{
	Person p1(10);
	cout<<p1<<endl;
}

operate++(),operate++(int),自增运算符重载

class MyInterer
{
friend ostream& operate<<(ostream &cout,Person &p1);//全局友元可以访问私有变量
public:
	MyInterer()
	{
		num = 0;
	}
	//重载前置++运算符,返回引用是为了一直对一个数据进行操作
	MyInterer& operate++()
	{
		num++;
		return *this;//返回自身
	}
	//重载后置++运算符,int是占位参数表示区分前置和后置,返回值因为是局部变量要不会非法操作
	MyInterer operate++(int)
	{
		MyInterer my =  *this;//先记录原本的
		num++;//再增加
		return my;//再返回
	}
private:
	int num;
}
ostream& operate<<(ostream &cout,Person &p1)//通过全局函数重载+,本质operat<<(cout,p)简化cout<<p
{
	cout<<p1.age;
	return cout;
}
void test01()
{
	MyInterer my1;
	cout<<++(++my1)<<endl;//返回引用一直对自己操作 2
	cout<my1<<endl;//已经加上 2
}
void test02()
{
	MyInterer my2;
	cout<<my2++<<endl;//0 不会(my2++)++这种写法因为是返回值不可修改
	cout<my2<<endl;//1
}

operate=() c++编译器还会给类增加第四个函数是operate=,进行值拷贝。所以还是会出现浅拷贝的问题,重复释放同一个堆区的内容,要用深拷贝解决

class Person
{
	int *m_age;
	Person(int age)
	{
		m_age = new int(age);//重新开辟内存,深拷贝
	}
	~Person()
	{
		if(m_age !=NULL)
		{
			delete m_age ;//析构函数要释放内存,这里就会暴露浅拷贝出现的问题所以要重载operate=使用深拷贝
			m_age = NULL;
		}
	}
	Person& operate=(Person &p)
	{
		m_age = p.age;//编译器本身是值拷贝
		if(m_age !=NULL)//先判断原本有没有数据,有的话先清空
		{
			delete m_age ;
			m_age = NULL;
		}
		m_age = new int(*p.age);//重新开辟内存,深拷贝
		return *this;//返回自身的引用才能连续操作
	}
};
void test()
{
	Person p1(10);
	Person p2(20);
	Person p3(30);
	p3 = p2 = p1;
}

operate==(),operate!=()关系运算符重载,自定义数据类型判断

class Person 
{
	int age;
	bool operate ==(Person &p)
	{
		if(this->age == p.age)
		{
			return true;
		}
		return false;
	}
	bool operate !=(Person &p)
	{
		if(this->age == p.age)
		{
			return false;
		}
		return true;
	}
};
void test()
{
	Person p1(10);
	Person p2(20);
	if(p1==p2)
	{
		cout<<"相等"<<endl;
	}
	else
	{
		cout<<"不相等"<<endl;
	}
	if(p1!=p2)
	{
		cout<<"不相等"<<endl;
	}
	else
	{
		cout<<"相等"<<endl;
	}

operate()(),很像函数调用所以叫仿函数,比较灵活没有固定写法

class MyPrint
{
	void operate()(string s)
	{
		cout<<s<<endl;
	}
};
class MyAdd
{
	int operate()(int a,int b)
	{
		return a+b;
	}
};
void test01()
{
	MyPrint myprint;
	myprint("test");//特别像函数调用
}
void test02()
{
	MyAdd myadd;
	myadd(100,100);
	cout<<MyAdd()(100,100)<<endl;//匿名函数对象
}

12.26重载有好多东西啊,只能明天再学继承和多肽了!--------------------------------------------------------------------------

标签:p1,int,void,c++,学习,Person,operate,age
From: https://blog.csdn.net/qq_45080494/article/details/144658045

相关文章

  • qt学习之增加checkBox
    在实际的开发过程中,有时会需要将单元格是控件居中的情况存在,发现加了布局之后,tablewidget的信号cellChanged无法响应,于是想了一个办法当checkBox的状态发生变化时,手动发送tablewidget改变的信号以下是两种在单元格中增加复选框的方法//第一种,setItem直接添加此处没有布局......
  • Flutter学习笔记:API
    本文更新于2024-12-26,使用Flutter3.3.3。官方文档:https://api.flutter.dev或https://api.flutter-io.cn目录dart:ui【UI库】枚举TextDirection——文本方向animation【动画库】类AnimatedBuilder——动画创建器Animation<T>——动画AnimationController——动画控制......
  • ssm软件工程专业师生互动学习网站5z68s(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、研究背景与意义随着信息技术的快速发展,软件工程专业的教育模式正经历深刻变革。构建一个软件工程专业师生互动学习网站,旨在打破传统教学的时空......
  • 2024-2025-1 20241401 《计算机基础与程序设计》 第十四周学习总结
    班级链接2024计算机基础与程序设计作业要求第十四周作业教材学习内容总结《C语言程序设计》第13-14章第13章文件操作二进制文件和文本文件:介绍了文件的两种基本类型,二进制文件和文本文件,以及它们的区别。文件的打开和关闭:介绍在C语言中打开和关闭文件的方式......
  • VScode中C/C++调试文件配置
    VScode中C/C++调试文件配置//launch.json{"version":"2.0.0","configurations":[{"name":"C/C++:gcc.exebuildanddebugactivefile",//调试配置名称"type":"......
  • 2024-2025-1 20241322 《计算机基础与程序设计》第十四周学习总结
    2024-2025-120241322《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK14这个作业的目标自学教材《C语言......
  • React—01—基本学习,如何在html中直接使用react;
     一、react的特点:   <script>标签这里要加一个“text/babel”,babel才知道这个<script>标签里要解析js代码,否则babel不会启动。     React组件是返回标签的JavaScript函数: 哪个组件是通过改变state实现可响应的,或者哪个组件拥有 这个state。......
  • 深度学习笔记——Transformer(上篇)
    大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的Transformer知识点,由于字数限制,分为上下篇发布。文章目录初识Transformer1.编码器-解码器架构解码器的额外结构2.自注意力机制(Self-AttentionMechanism)解码器中的注......
  • c++:谁管谁叫爹
    谁管谁叫爹《咱俩谁管谁叫爹》是网上一首搞笑饶舌歌曲,来源于东北酒桌上的助兴游戏。现在我们把这个游戏的难度拔高一点,多耗一些智商。不妨设游戏中的两个人为A和B。游戏开始后,两人同时报出两个整数......
  • 【深度学习基础|知识概述】基础数学和理论知识中的概率与统计知识:概率与概率分布、最
    【深度学习基础|知识概述】基础数学和理论知识中的概率与统计知识:概率与概率分布、最大似然估计、损失函数的应用,附代码。【深度学习基础|知识概述】基础数学和理论知识中的概率与统计知识:概率与概率分布、最大似然估计、损失函数的应用,附代码。文章目录【深度学习基......