C++进阶篇—1

学习C++怎么进阶? C++是目前编程语言中学习成本比较高的语言之一,C++在图形、音视频处理,通信,游戏,后端服务方面应用还比较广泛,我认为需要C++学习进阶有如下几个步骤: 1、看一下C++方面的编程书籍 1)《C++Primer》,《C++编程思想》这初级读本是所有学习C++的人必须啃的书,C++的知识点比较全。 2)《Effective C++》、《MoreEffective C++》、《C++... 阅读详情
  • 面向对象编程-----------------------------------------------难点
  • 类和对象
  • 类的成员变量
  • 访问修饰符
  • 构造与析构函数----------------------------------------------重点
  • this指针---------------------------------------------------重点

何为面向对象?
所谓面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统(模拟现实)

1.对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系

2.面向对象不是某一种语言的特性,而是一种编程思想

抽象

  • 从具体事物抽取共同的本质特征

C++中的类

  • 类是一种将抽象转换为用户定义类型的工具

  • 将数据表示和操纵数据的方法组合成一个整体

  • 类的实例为对象

  • 类中变量和函数称为成员
    在这里插入图片描述
    类的声明

  • 使用**class**/struct关键字声明类型
    在这里插入图片描述
    类的学习
    Land1.h

#pragma once
#include <string>
#include <iostream>


/**
* .hpp文件一般包括实现的内联函数  通常用于模板类这种声明与实现共存的情况
* 建议:只要不是纯模板 一律使用.h作为头文件后缀,使用.cpp文件作为函数的实现文件
*/

using namespace std;

class Land1
{
public:
	string name;  //地主的名称
	long score;		//地主的积分
	int cards[20];		//地主的手牌数组
public:
	Land1();				//构造函数的声明
	~Land1();				//析构函数的声明
	//inline void touchcard(int cardcount)  //默认内联函数
	//{
	//	cout << name << "开始摸牌" << cardcount << "张牌" << endl;
	//}
	//void showscore()
	//{
	//	cout << name << "当前的积分为" << score << endl;
	//}
	void touchcard(int); //声明牌方法
	void showscore(); //声明的显示积分方法

protected:

};

Land1.cpp

#include "Land1.h"


Land1::Land1()   //实现了默认构造函数
{
}


Land1::~Land1()
{
}

//实现摸牌方法
void Land1::touchcard(int cardCount)
{
	cout << name << "开始摸牌" << cardCount << "张牌" << endl;
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件

using namespace std;

int main()
{
	Land1 la1; //声明了一个Land1类型的变量 la1
	//调用对象的成员方法
	int n;
	cin >> n;
	la1.name = "冯是";
	la1.touchcard(n);
	return 0;
}

访问修饰符

常见访问修饰符

  • public:修饰得分成员在任意地方都可以访问
  • pravate:修饰的成员只能够在类中或者友元函数中可以访问
  • protected:修饰的成员可以在类中函数、子类函数及友元函数中访问

修饰成员

将修饰关键字放置在类定义的大括号中,添加冒号
在这里插入图片描述
私有属性怎么修改
Land2.h

#pragma once

#include <string>

using namespace std;

class Land2
{
	//省略了private
	string name;
	long score; //解决积分为负数错误的方法,将成员变量score进行隐藏并封装
	int cards[20];
public:
	

	Land2();
	~Land2();

	void show();

	//使用方法/函数实现对成员变量的封装Get/Set方法
	void SetScore(long lscore)
	{
		if (lscore < 0)
			score = 0;//如果传入的积分是非法情况, 那么积分默认为0;
		else
			score = lscore;//积分为正数时, 才进行赋值操作, 这里就通过条件判断,封装了score的赋值过程
	}
	string GetName();

	void SetName(string na);
};

Land2.cpp

#include "Land2.h"

#include <iostream>

Land2::Land2()
{
}


Land2::~Land2()
{
}

void Land2::show()
{
	cout << name << "得了" << score << "分" << endl;
}

string Land2::GetName()
{
	return name;
}

void Land2::SetName(string na)
{
	name = na;
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"

using namespace std;

int main()
{
	//Land1 la1; //声明了一个Land1类型的变量 la1
	////调用对象的成员方法
	//int n;
	//cin >> n;
	//la1.name = "冯是";
	//la1.touchcard(n);
	//return 0;

	Land2 la2;
	//la2.name = "1231";
	//注意: 模拟为地主修改积分
	//la2.score = 100;  //私有属性,是更改不了的
	la2.SetScore(-100);
	la2.SetName("飞哥");
	cout << la2.GetName() << endl;
	la2.show();
}

在这里插入图片描述
构造函数

  1. 以类名作为函数名
  2. 无返回值类型

作用
3. 初始化对象的数据成员
4. 类对象被创建时,编译器为对象分配内存空间并自动调用构造函数以完成成员的初始化

构造函数的种类
5. 无参构造
6. 一般构造
7. 拷贝构造
在这里插入图片描述
注意:

  1. 如果创建的类中未书写任何构造函数,系统会自动生成默认的无参数构造函数(函数为空, 什么都不做)
  2. 如果书写了构造函数,系统就不会再自动生成默认构造;如果希望有一个这样的无参构造函数,需要自己显示地书写出来。

Land2.h

#pragma once

#include <string>
#include <memory>

using namespace std;

class Land2
{
	//省略了private
	string name;
	long score; //解决积分为负数错误的方法,将成员变量score进行隐藏并封装
	int cards[20];
public:
	
	Land2();//默认构造
	~Land2();

	void show();

	//使用方法/函数实现对成员变量的封装Get/Set方法
	void SetScore(long lscore)
	{
		if (lscore < 0)
			score = 0;//如果传入的积分是非法情况, 那么积分默认为0;
		else
			score = lscore;//积分为正数时, 才进行赋值操作, 这里就通过条件判断,封装了score的赋值过程
	}
	string GetName();

	void SetName(string na);
};


Land2.cpp

#include "Land2.h"

#include <iostream>

Land2::Land2()
{
	//一般使用构造函数进行成员变量的初始化
	name = "默认地主";
	score = 0;
	//将用户的手牌数组初始化为0
	memset(cards, 0, sizeof(cards));
	cout << "Land2的无参构造函数(默认构造)被调用!" << endl;
	cout << "初始化的结果如下:" << endl;
	cout << "名称:" << name << endl;
	cout << "积分:" << score << endl;
	cout << "手牌数组:";
	for (int i = 0; i < sizeof(cards) / sizeof(cards[0]); i++)
	{
		cout << cards[i] << ", ";
	}
	cout << endl;
}


Land2::~Land2()
{
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"

using namespace std;

int main()
{
	//Land2 land2;
	Land2 land2; 
}

显示

Land2的无参构造函数(默认构造)被调用!
初始化的结果如下:
名称:默认地主
积分:0
手牌数组:0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

带类构造 ——函数重载
在这里插入图片描述
Land3.h

#pragma once
#include <iostream>
#include <string>

using namespace std;

class Land3
{
public:
	//构造函数的重载规则与普通函数的重载相同
	Land3();
	Land3(int); //如果构造函数中,只有一个带参 可以简化:Land3 L3 = 50;
	Land3(string, string);//带参构造
	~Land3();

	void ShowInfo();

	string GetName() { return m_name; }
	void SetName(string val) { m_name = val; }
	string Getdesc() { return m_desc; }
	void Setdesc(string val) { m_desc = val; }
	int Getage() { return m_age; }
	void Setage(int val)
	{
		if (val < 0)
			m_age = 18;
		else
			m_age = val;
	}

protected:

private:
	string m_name;
	string m_desc;
	int m_age;

};

Land3.cpp

#include "Land3.h"



Land3::Land3()
{
	cout << "默认构造" << endl;

}

Land3::Land3(int age)
{
	Setage(age);
	cout << "调用带参构造:Land3::Land3(int age)" << endl;
}

Land3::Land3(string name, string desc) : m_name(name), m_desc(desc) //初始化参数列表简写
{
	//m_name = name;//等价写法  SetName(name);
	//m_desc = desc;
	cout << "调用带参构造:Land3::Land3(string name, string desc)" << endl;
}

void Land3::ShowInfo()
{
	cout << m_desc << m_name << endl;
}

Land3::~Land3()
{
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"
#include "Land3.h"

using namespace std;

int main()
{
	Land3 L1; //在栈内存中直接分配内存,(宝贵)
	Land3 L2("马", "架体");
	Land3 l3(35);
	Land3 L4 = 46;
	L2.ShowInfo();

	Land3* l5 = new Land3("jieke", "huichuangali");//指针型,在堆内存里面新分配一个空间
	l5->ShowInfo();
}

显示结果

默认构造
调用带参构造:Land3::Land3(string name, string desc)
调用带参构造:Land3::Land3(int age)
调用带参构造:Land3::Land3(int age)
架体马
调用带参构造:Land3::Land3(string name, string desc)
huichuangalijieke

栈内存和堆内存
**栈内存:**由程序自动向操作系统申请分配以及回收,速度快,使用方便,但程序员无法控制。若分配失败,则提示栈溢出错误。注意,const局部变量也储存在栈区内,栈区向地址减小的方向增长。

**堆内存:**程序员向操作系统申请一块内存,当系统收到程序的申请时,会遍历一个记录空闲内存地址的链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。分配的速度较慢,地址不连续,容易碎片化。此外,由程序员申请,同时也必须由程序员负责销毁,否则则导致内存泄露。

析构函数

  1. 对象过期时自动调用的特殊成员函数
  2. 析构函数一般用来完成清理工作
  3. 析构函数的名称是在类名前加上==~==
  4. 析构函数没有参数, 只能有一个
    在这里插入图片描述
    注意:
    1、 析构函数用来释放对象使用的资源,并销毁对象的非static(静态)数据成员
    2、无论何时一个对象被销毁, 都会自动调用其析构函数(隐式结构)
    land3.cpp
#include "Land3.h"



Land3::Land3()
{
	cout << "默认构造" << endl;

}

Land3::Land3(int age)
{
	Setage(age);
	cout << "调用带参构造:Land3::Land3(int age)" << endl;
}

Land3::Land3(string name, string desc) : m_name(name), m_desc(desc) //初始化参数列表简写
{
	//m_name = name;//等价写法  SetName(name);
	//m_desc = desc;
	cout << "调用带参构造:Land3::Land3(string name, string desc)" << endl;
}

void Land3::ShowInfo()
{
	cout << m_desc << m_name << endl;
}

Land3::~Land3()
{
	cout << m_name << "被释放" << endl; //栈内存自动被释放
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"
#include "Land3.h"

using namespace std;

int main()
{
	Land3 L1; //在栈内存中直接分配内存,(宝贵)
	Land3 L2("马", "架体");
	Land3 l3(35);
	Land3 L4 = 46;
	L2.ShowInfo();

	Land3* l5 = new Land3("jieke", "huichuangali");//指针型,在堆内存里面新分配一个空间
	l5->ShowInfo();

	//当对象使用完毕时,记得delete 释放内存(堆内存)
	delete l5;
}

实现结果

默认构造
调用带参构造:Land3::Land3(string name, string desc)
调用带参构造:Land3::Land3(int age)
调用带参构造:Land3::Land3(int age)
架体马
调用带参构造:Land3::Land3(string name, string desc)
huichuangalijieke
jieke被释放
被释放
被释放
马被释放
被释放

使用类创建对象

第一种实例化对象
栈内存中创建:类似声明变量
在这里插入图片描述
第二种实例化方式
在碓内存中创建:需要new关键字
在这里插入图片描述
练习
在这里插入图片描述
数组的替代品——容器

向量容器Vector

  • 动态数组,可以在运行阶段设置长度
  • 具有数组的快速索引方式
  • 可以插入和删除元素

定义和初始化

vector<double> vec1;
vector<string> vec2(5);
vector<int> vec3(20, 998);

在这里插入图片描述
Land3.h

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>

using namespace std;

class Land
{
private:
	string m_NickName;
	string m_Sex;
	int m_Gold;
	long m_Exp;
	vector<int> packCards; //默认的一副牌,从1到54
	vector<int> surplusCards; //摸牌后剩余的牌
	vector<int> currCards; //当前玩家的手牌数组
	bool isContains(int); //剩余牌中是否包含cardNum这个牌面

	void deleteCard(vector<int>&, int); //删除集合中的数字

	string getColor(int);//获得牌的花色
	string getValue(int);//获得牌面

public:
	Land();
	Land(string);
	Land(string, string, int, long);
	~Land();

	string GetNickName() { return m_NickName; }
	void SetNickName(string NickName) { m_NickName = NickName; }
	string GetSex() { return m_Sex; }
	void SetSex(string Sex) { m_Sex = Sex; }
	int GetGold() { return m_Gold; }
	void SetGold(int val) { m_Gold = val; }
	long GetExp() { return m_Exp; }
	void SetExp(long val) { m_Exp = val; }

	void TouchCard(int);//摸牌

	void ShowInfo();

	void InitCards();//初始化packCards、surplusCards、currCards

	void ShowCards(const vector<int>&); //显示集合中的牌面 传引用 内存效率会更高,const防止传引用误更改引用的值
protected:

};

Land3.cpp

#include "Land.h"

Land::Land()
{
	SetNickName("默认地主");
	SetSex("保密");
	SetExp(0);
	SetGold(100);
	cout << "Land()" << endl;
	InitCards();
}

Land::Land(string nickname) : m_NickName(nickname)
{
	SetSex("保密");
	SetExp(0);
	SetGold(100);
	cout << "Land(string nickname)" << endl;
	InitCards();

}

Land::Land(string nickname, string sex, int gold, long exp) : m_NickName(nickname), m_Sex(sex), m_Gold(gold), m_Exp(exp)
{
	cout << "Land(string nickname, string sex, int gold, long exp)" << endl;
	InitCards();
}

void Land::ShowInfo()
{
	cout << "昵称:" << GetNickName() << endl;
	cout << "性别:" << GetSex() << endl;
	cout << "金币:" << GetGold() << endl;
	cout << "经验:" << GetExp() << endl;
}

void Land::InitCards()
{
	//生成默认的一幅扑克牌
	for (int i = 0; i < 54; i++)
	{
		packCards.push_back(i + 1);
		surplusCards.push_back(packCards.at(i));
	}
	currCards.clear();

	ShowCards(surplusCards);
}

void Land::ShowCards(const vector<int>& cards)
{
	////C语言的习惯
	//for (int i = 0; i < cards.size(); i++)
	//{
	//	cout << cards[i] << ", ";
	//}
	//cout << endl;

	////c++, 使用迭代器
	//for (vector<int>::const_iterator iter = cards.begin(); iter != cards.end(); iter++)
	//{
	//	cout << *iter << ", ";
	//}
	//cout << endl;

	////使用c++11 的类型推断 auto
	//for (auto iter = cards.begin(); iter != cards.end(); iter++)
	//{
	//	cout << *iter << ", ";
	//}
	//cout << endl;

	//使用c++11 for区间遍历
	for (auto card : cards)
	{
		cout << card << ":" << getColor(card) << "-" << getValue(card) << ", ";
	}
	cout << endl;

	////使用算法的方式, 将容器的内容复制到cout 绑定的迭代器中
	////要用到两个头文件 #include<iterator> #include<algorithm>
	//copy(cards.cbegin(), cards.cend(), ostream_iterator<int>(cout, ", "));
	//cout << endl;
}

void Land::TouchCard(int cardCount)
{
	srand(time(NULL)); //时间种子
	//随机生成一张剩余牌集合中有的牌, 添加到currCards集合中, 从surrplusCards中删除这张牌
	for (int i = 0; i < cardCount; i++)
	{
		int randIndex = rand() % 54; //0-53之间的随机数字
		//判断:随机生成的这张牌是否在剩余牌集合中
		if (isContains(packCards[randIndex]))
		{
			currCards.push_back(packCards[randIndex]); //将摸的牌放入当前手牌数组
			//在剩余排钟删除摸的牌
			deleteCard(surplusCards, packCards[randIndex]);
		}
		else
		{
			i--;//重新摸牌
		}
	}
	cout << "地主摸牌:当前手牌如下:" << endl;
	ShowCards(currCards);
	cout << "地主摸牌后:剩余牌面如下:" << endl;
	ShowCards(surplusCards);
}

bool Land::isContains(int cardNum)
{
	////普通青年的做法:
	//for (int i = 0; i < surplusCards.size(); i++)
	//{
	//	if (surplusCards[i] == cardNum)
	//	{
	//		return true;
	//	}
	//}
	//return false;

	//使用算法来查找
	vector<int>::iterator iter = find(surplusCards.begin(),surplusCards.end(), cardNum);
	/*if (iter == surplusCards.end())
	{
		return false;
	}
	return true;*/
	return iter != surplusCards.end();
}

void Land::deleteCard(vector<int>& cardVec, int card)
{
	////普通青年的做法
	//for (auto iter = cardVec.begin(); iter != cardVec.end();)
	//{
	//	if (*iter == card)
	//	{//如果找到就删除
	//		iter = cardVec.erase(iter);//这里返回值指向已删除的下一个元素
	//	}
	//	else
	//	{
	//		++iter;//继续判断下一个元素是否相同
	//	}
	//}

	//使用算法删除
	auto iter = find(cardVec.begin(), cardVec.end(), card);
	if (iter != cardVec.end())
	{
		cardVec.erase(iter);
	}
}

string Land::getColor(int card) // 注意这里 card 不是下标
{
	if (card == 53) return "小王";
	if (card == 54) return "大王";
	string colors[] = {
		"黑桃", "红心", "方块", "梅花"
	};
	return colors[(card - 1) / 13];
}

string Land::getValue(int card)
{
	if (card == 53) return "Black Joker";
	if (card == 54) return "Red Joker";
	string value[] = {
		"A", "2", "3", "4", "5", "6", "7", "8",
		"9", "10", "J", "Q", "K"
	};
	return value[(card - 1) % 13];
}

Land::~Land()
{
	cout << GetNickName() << "被释放" << endl;
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"
#include "Land3.h"
#include "Land.h"

using namespace std;

int main()
{
	Land* ptr_L1 = new Land(); 
	ptr_L1->ShowInfo();
	Land* ptr_L2 = new Land("专业斗地主");
	ptr_L2->ShowInfo();
	Land* ptr_L3 = new Land("傻瓜");
	ptr_L3->ShowInfo();

	ptr_L2->TouchCard(20);

	delete ptr_L1;
	delete ptr_L2;
	delete ptr_L3;

	return 0;
}

结果

Land()
1:黑桃-A, 2:黑桃-2, 3:黑桃-3, 4:黑桃-4, 5:黑桃-5, 6:黑桃-6, 7:黑桃-7, 8:黑桃-8, 9:黑桃-9, 10:黑桃-10, 11:黑桃-J, 12:黑桃-Q, 13:黑桃-K, 14:红心-A, 15:红心-2, 16:红心-3, 17:红心-4, 18:红心-5, 19:红心-6, 20:红心-7, 21:红心-8, 22:红心-9, 23:红 心-10, 24:红心-J, 25:红心-Q, 26:红心-K, 27:方块-A, 28:方块-2, 29:方块-3, 30:方块-4, 31:方块-5, 32:方块-6, 33:方块-7, 34:方块-8, 35:方块-9, 36:方块-10, 37:方块-J, 38:方块-Q, 39:方块-K, 40:梅花-A, 41:梅花-2, 42:梅花-3, 43:梅花-4, 44:梅花-5, 45:梅花-6, 46:梅花-7, 47:梅花-8, 48:梅花-9, 49:梅花-10, 50:梅花-J, 51:梅花-Q, 52:梅花-K, 53:小王-Black Joker, 54:大王-Red Joker,
昵称:默认地主
性别:保密
金币:100
经验:0
Land(string nickname)
1:黑桃-A, 2:黑桃-2, 3:黑桃-3, 4:黑桃-4, 5:黑桃-5, 6:黑桃-6, 7:黑桃-7, 8:黑桃-8, 9:黑桃-9, 10:黑桃-10, 11:黑桃-J, 12:黑桃-Q, 13:黑桃-K, 14:红心-A, 15:红心-2, 16:红心-3, 17:红心-4, 18:红心-5, 19:红心-6, 20:红心-7, 21:红心-8, 22:红心-9, 23:红 心-10, 24:红心-J, 25:红心-Q, 26:红心-K, 27:方块-A, 28:方块-2, 29:方块-3, 30:方块-4, 31:方块-5, 32:方块-6, 33:方块-7, 34:方块-8, 35:方块-9, 36:方块-10, 37:方块-J, 38:方块-Q, 39:方块-K, 40:梅花-A, 41:梅花-2, 42:梅花-3, 43:梅花-4, 44:梅花-5, 45:梅花-6, 46:梅花-7, 47:梅花-8, 48:梅花-9, 49:梅花-10, 50:梅花-J, 51:梅花-Q, 52:梅花-K, 53:小王-Black Joker, 54:大王-Red Joker,
昵称:专业斗地主
性别:保密
金币:100
经验:0
Land(string nickname)
1:黑桃-A, 2:黑桃-2, 3:黑桃-3, 4:黑桃-4, 5:黑桃-5, 6:黑桃-6, 7:黑桃-7, 8:黑桃-8, 9:黑桃-9, 10:黑桃-10, 11:黑桃-J, 12:黑桃-Q, 13:黑桃-K, 14:红心-A, 15:红心-2, 16:红心-3, 17:红心-4, 18:红心-5, 19:红心-6, 20:红心-7, 21:红心-8, 22:红心-9, 23:红 心-10, 24:红心-J, 25:红心-Q, 26:红心-K, 27:方块-A, 28:方块-2, 29:方块-3, 30:方块-4, 31:方块-5, 32:方块-6, 33:方块-7, 34:方块-8, 35:方块-9, 36:方块-10, 37:方块-J, 38:方块-Q, 39:方块-K, 40:梅花-A, 41:梅花-2, 42:梅花-3, 43:梅花-4, 44:梅花-5, 45:梅花-6, 46:梅花-7, 47:梅花-8, 48:梅花-9, 49:梅花-10, 50:梅花-J, 51:梅花-Q, 52:梅花-K, 53:小王-Black Joker, 54:大王-Red Joker,
昵称:傻瓜
性别:保密
金币:100
经验:0
地主摸牌:当前手牌如下:
16:红心-3, 54:大王-Red Joker, 31:方块-5, 6:黑桃-6, 10:黑桃-10, 33:方块-7, 38:方块-Q, 5:黑桃-5, 27:方块-A, 24:红心-J, 12:黑桃-Q, 44:梅花-5, 49:梅花-10, 8:黑桃-8, 28:方块-2, 42:梅花-3, 36:方块-10, 41:梅花-2, 22:红心-9, 14:红心-A,
地主摸牌后:剩余牌面如下:
1:黑桃-A, 2:黑桃-2, 3:黑桃-3, 4:黑桃-4, 7:黑桃-7, 9:黑桃-9, 11:黑桃-J, 13:黑桃-K, 15:红心-2, 17:红心-4, 18:红心-5, 19:红心-6, 20:红心-7, 21:红心-8, 23:红心-10, 25:红心-Q, 26:红心-K, 29:方块-3, 30:方块-4, 32:方块-6, 34:方块-8, 35:方块-9, 37:方块-J, 39:方块-K, 40:梅花-A, 43:梅花-4, 45:梅花-6, 46:梅花-7, 47:梅花-8, 48:梅花-9, 50:梅花-J, 51:梅花-Q, 52:梅花-K, 53:小王-Black Joker,
默认地主被释放
专业斗地主被释放
傻瓜被释放

this关键字

this指针

  • 每个成员函数(包括构造和析构)都有一个this指针
  • this指针指向调用对象,既可以通过this关键字访问当前对象的成员
    在这里插入图片描述
  • 可以用来返回当前对象的引用
    在这里插入图片描述
    Land3.h
#pragma once
#include <iostream>
#include <string>

using namespace std;

class Land3
{
public:
	//构造函数的重载规则与普通函数的重载相同
	Land3();
	Land3(int); //如果构造函数中,只有一个带参 可以简化:Land3 L3 = 50;
	Land3(string, string);//带参构造
	~Land3();

	void ShowInfo();

	string GetName() { return m_name; }
	void SetName(string val) { m_name = val; }
	string Getdesc() { return m_desc; }
	void Setdesc(string val) { m_desc = val; }
	int Getage() { return m_age; }
	void Setage(int val) 
	{
		if (val < 0)
			m_age = 18;
		else
			m_age = val;
	}

	void InitScores(); //初始化学生成绩数组,默认分配一个元素空间
	void AddScore(float); //向scores数组中添加一个分数

	//书写函数, 要求返回学霸对象
	Land3& GetSuperScholar(Land3&); //const;
	float GetTotal();

protected:

private:
	string m_name;
	string m_desc;
	int m_age;
	int scoreCount;//学生的成绩个数
	float* scores;//学生的分数数组
};

Land3.cpp

#include "Land3.h"



Land3::Land3()
{
	cout << "默认构造" << endl;

}

Land3::Land3(int age)
{
	Setage(age);
	cout << "调用带参构造:Land3::Land3(int age)" << endl;
	InitScores();
}

Land3::Land3(string name, string desc) : m_name(name), m_desc(desc) //初始化参数列表简写
{
	//m_name = name;//等价写法  SetName(name);
	//m_desc = desc;
	cout << "调用带参构造:Land3::Land3(string name, string desc)" << endl;
	InitScores();
}

void Land3::ShowInfo()
{
	cout << m_desc << m_name << endl;
	for (int i = 0; i < scoreCount - 1; i++)
	{
		cout << this->scores[i] << "\t";
	}
	cout << endl;
}

//void Myshow(const Land3* thiz) //c的写法 this在c++中是函数的隐含的第一个参数;
//{
//	thiz->AddScore;
//}

void Land3::InitScores()
{
	this->scores = new float[1];
	this->scoreCount = 1;
}

void Land3::AddScore(float score)
{
	this->scores[this->scoreCount - 1] = score;
	//1、创建一个新数组、分配scorecount + 1个空间
	//2、复制一个元素组的内容到新数组中
	//3、scoreCount++
	//4、scores指向新数组

	float* newScores = new float[scoreCount + 1];
	float* oldScores = scores;
	memcpy(newScores, scores, sizeof(float) * scoreCount);
	scoreCount++;
	scores = newScores;
	delete oldScores;
}

float Land3::GetTotal()
{
	float sum = 0;
	for (int i = 0; i < scoreCount - 1; i++)
	{
		sum += scores[i];
	}
	return sum;
}

/*返回学霸对象
*@param otherStu 要对比的另外一个学生对象
*@return 返回总分比较大的那个学生对象
*/
 Land3& Land3::GetSuperScholar(Land3& otherStu)
{
	//分别计算两个学生的总分
	if (this->GetTotal() > otherStu.GetTotal())
	{
		return *this;//返回当前对象的引用
	}
	else
	{
		return otherStu;
	}
}

Land3::~Land3()
{
	cout << m_name << "被释放" << endl; //栈内存自动被释放
	//delete this->scores;
}

main.cpp

#include <iostream>
#include "Land1.h"    //如果要实用类,必须要包含类的头文件
#include "Land2.h"
#include "Land3.h"
#include "Land.h"

using namespace std;

int main()
{
	/*Land* ptr_L1 = new Land(); 
	ptr_L1->ShowInfo();
	Land* ptr_L2 = new Land("专业斗地主");
	ptr_L2->ShowInfo();
	Land* ptr_L3 = new Land("傻瓜");
	ptr_L3->ShowInfo();

	ptr_L2->TouchCard(20);

	delete ptr_L1;
	delete ptr_L2;
	delete ptr_L3;*/

	Land3* ptrL1 = new Land3("diyihfdis", "asdjfha");

	ptrL1->AddScore(78.9f);
	ptrL1->AddScore(100.2f);
	ptrL1->AddScore(68.5f);
	ptrL1->AddScore(45.7f);
	ptrL1->AddScore(99.9f);
	ptrL1->ShowInfo();

	Land3 L2( "akjsdkj", "sjdhfh" );
	L2.AddScore(56.8f);
	L2.AddScore(98.4f);
	L2.AddScore(86.4f);
	L2.AddScore(45.6f);
	L2.AddScore(76.8f);

	Land3& scholar1 = L2.GetSuperScholar(*ptrL1); //返回ptrL1的引用
	Land3& scholar2 = ptrL1->GetSuperScholar(L2);
	cout << "学霸是:" << scholar1.GetName() << endl;
	cout << "学霸是:" << scholar2.GetName() << endl;

	delete ptrL1;

	return 0;
}

结果

调用带参构造:Land3::Land3(string name, string desc)
asdjfhadiyihfdis
78.9    100.2   68.5    45.7    99.9
调用带参构造:Land3::Land3(string name, string desc)
学霸是:diyihfdis
学霸是:diyihfdis
diyihfdis被释放
akjsdkj被释放
C++——进阶之路 我一直想是不是拜师,学学艺。有着大佬的庇佑,那岂不是轻车熟路,畅通无阻。后来,我又想了想。完全不用!按如今的环境,以及各种情况,综合因素,不可抗力,等等数不清的原因——不可能。 那么,究竟该如何在C++的道路上进阶。如果你是从娘胎里就开始编程的,有着这一个会编程的爹。那真是——如获至宝(苦命的孩子)。那么,我们半路出身的,野生的,该如何学习。又没有这么厉害的爹,考上大学都已经是自求多福了。选了计算机专业,希望以后出来能挣大钱。结果却是没日没夜的996。说了这么多,你还教人家... 阅读详情

相关推荐

2024年C C++最全Qt之QGraphicsView进阶篇(1),C C++开发指南

场景和视图的渲染函数的不同在于 QGraphicsScene::render() 使用场景坐标,而 QGraphicsView::render() 使用视图坐标。QGraphicsScene::render() 经常用于打印未变换场景中的整块,例如一块图形数据或是打印一个文本文档。当视图接收到拖拽事件,GraphicsView 框架会将拖拽事件翻译为 QGraphicsSceneDragDropEvent 事件,再发送到场景,场景接管事件,再把事件发送到光标下接受拖拽的第一个图元。知识点,真正体系化!

2401_84976741的博客 1237

任鸟飞逆向C++进阶篇

【课程简介】本课程为任鸟飞逆向C++进阶篇,注重基础理论的务实和简单功能的实现,学员学成后,可独立判断、分析和解决逆向问题、独立编写通用辅助。本套课程不只是一套深入学习C++的课程,更是一套深入学习汇编逆向课程、外挂与反外挂、软件安全的课程。逆向思路技术随笔,请关注我的CSDN博客:https://blog.csdn.net/qq_36553941 欢迎大家来学习交流,活动折扣等信息也在其第一时间发布。PS: 课程中工具包、源码、课件请关注第一章的第一节的随课课件,工欲望善其事,必先利其器! 【学前预备知识】任鸟飞逆向C++系列课程是一条精心安排为掌握汇编逆向、外挂与反外挂、软件安全的学习路线,包括但不限于 基础篇、进阶篇(本篇)、高级篇、实战篇等,所以为保证您能学有所成请在学习本篇之前务必掌握基础篇!!!基础篇CSDN学院链接:https://edu.csdn.net/course/detail/30509 【学员学成收获】1、C++编程语言进阶。2、游戏逆向分析进阶。3、游戏安全对抗理论进阶。4、独立编写通用辅助。 

c++在一个cpp文件中调用另一个cpp文件的函数的两种方法

有时候写代码为了简便,会将一些函数方法单独在一个cpp的源文件中定义,然后在另一个源文件中需要用到自定义的函数时直接调用就可以了!学过c++的人可能最熟悉的方法还是利用头文件来进行调用,其实还有一种c语言当中的方法一般情况下同样可以适用与c++中! 方法1:创建头文件 举个简单的例子: 首先创建一个method.h头文件,声明一个求最大值的函数max(int x,int y),然后再创建一个同名的源文件method.cpp,在该文件中实现函数max(int x,int y)的功能。代码如下: //metho

weixin_43350361的博客 6万+

C++编程:进阶阶段

本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。

qq_52737907的博客 3753

【C++】使用 yaml-cpp 库操作 YAML

配置文件有利于我们灵活配置工程,解决大量重复劳动,也方便调试。YAML 是一种人类可读的数据序列化格式,它使用缩进和特定的符号来表示数据结构。在本文中,我们将详细介绍如何在 C++ 中使用yaml-cpp库来解析和生成 YAML 格式的数据。

coco的专栏 4966

C++ 一个函数调用其他.cpp文件中的函数

使用VC或VS创建C++项目的时候,会自动产生许多文件夹,其中有一个文件夹->源文件: 在该文件下可以自定义许多.cpp文件,但是需要注意的是这里面的各个文件只能有一个文件中含有main()函数, 而且各个文件中不能使用相同的函数名进行定义; 那么要那么多文件放在项目中有什么用呢? 当然这里C++是提供一个文件调用其他文件中函数的功能的, 这就可以让我们自定义一个只包含main()...

⚡ 4万+

C++进阶篇1:数组的运用

数组的定义与特性一维数组与多维数组的区别静态数组与动态数组的对比数组的优缺点总结推荐进一步学习的数据结构(如链表、哈希表)

m0_61142723的博客 630

【log4】c++日志工具之——log4cpp

1、log4cpp概述 Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试; 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等; 可以动态控制日志记录级别,在效率和功能中进行调整; 所有配置可以通过配置文件进行动态调整; 多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(...

我的笔记本 8046

C++进阶篇1:字符串

C++ STL是Standard Template Library的简称,中文名标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。本问主要介绍了字符串的智能指针auto_ptr和相关成员函数。

小小羊 342

C++ Yaml文件解析安装及使用 yaml-cpp

C++ Yaml文件解析安装及使用安装 yaml-cpp克隆官方库编译 yaml-cpp示例代码robot.cpprobot.yaml编译 robot.cpp运行结果难点分析与总结什么是 .a 与 .so 文件静态链接库(.a) 与动态链接库(.so)静态链接库动态链接库g++(gcc)编译选项参考文章 安装 yaml-cpp 克隆官方库 git clone https://github.co...

Fourier_Legend的博客 2万+

c++ 利用yaml-cpp读写yaml配置文件

在程序员的开发生涯中,读写配置文件必不可少。 配置文件有利于我们灵活配置工程,解决大量重复劳动,也方便调试。 配置文件的格式有很多,最简单的有一行一行的文本,也有像 json、xml、protocol buffer 这样结构化的格式,当然也有 yaml 这种格式。 今天的博文介绍的是如何在 C++ 开发中利用 yaml-cpp 开源库读写 yaml 配置文件。 如果有 Python 开发经验的同学,可能知道用 Python 读取 yaml 是再简单不过了,但是 C++ 麻烦一点,它需要你自己下载源码然后编译

newbeixue的博客 4011

白骑士的C++教学进阶篇 2.1 指针与引用

指针和引用是C++中强大的工具,理解它们的区别和使用场景对编写高效、灵活的程序至关重要。指针提供了直接操作内存的能力,适用于动态内存分配和复杂数据结构,而引用提供了一种更简洁的语法,适用于函数参数和返回值优化。在编程实践中,合理选择使用指针或引用可以大大提高代码的可读性和性能。希望通过本篇博客的介绍,您能更好地掌握指针和引用的用法,为深入学习C++奠定坚实的基础。

JeremyTC的博客 1120

C++从入门到进阶的系列书籍推荐(22本书)

要多读书,读好书!一本书要多读几遍才好,每次都可能有新的收获!特别在是有一定的工作年限和工作经验之后!读书百遍,其义自见! 下面就给大家推荐一下C++程序员进阶需要读的经典书籍: 1、C++入门书籍 C++是在C语言的基础上发展而来的,要学习C++之前需要先学习C语言。有了C语言基础之后再去学习C++。 1.1、C语言程序设计(谭浩强) 该书被公认为学习C语言程序设计的优秀教材,被全国大多数高校选用,是学习C语言的主流用书。本书比较通俗易懂,是初入者必备的书籍。 ........

dvlinker的技术专栏 4万+

C++系列(三)---进阶篇(1)

C++

qq_27154853的博客 722

模拟电子课设-半导体直流稳压电源的设计和测试

1、学习直流稳压电源的设计方法; 2、研究直流稳压电源的设计方案; 3、掌握直流稳压电路的调试及主要指标的测试方法。二、设计要求和技术指标 1、设计要求1)、设计一个能输出5V-12V连续可调的直流稳压电源,或±12V的直流稳压电源; 2)、根据设计要求和技术指标设计好电路,选好元件及参数,要求绘出原理图,并用Protel 99SE/DXP画出印制板图; 3)、在万能板或面包板上制作一台直流稳压电源; 4)、测量直流稳压电源的稳压系数; 5)、测量直流稳压电源的内阻; 6)、拟定测试方案和设计步

GJZGRB的博客 1966

abb机器人指令手册_ABB机器人配置圆形输送链跟踪

更多内容请点击上方ABB机器人实战技巧关注也可点击公众号下方往期经典浏览更多内容转载请先后台留言,大家一起支持原创,推动机器人使用和发展本公众号对各类ABB机器人应用,仿真,毕业设计提供技术支持,详细后台留言本公众号诚挚希望与各机器人培训机构,机器人使用单元合作,提供技术支持,详细后台留言1. 通常的机器人输送链跟踪,均为直线输送链跟踪,例如下图2. 有些情况,输送链为圆形,例如...

weixin_39849894的博客 2035

Cpp入门基础

定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中 即为命名空间的成员。命名空间中可以定义变量/函数/类型等。namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下 ⾯的rand不在冲突了。C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。

2401_86658278的博客 4826

海思SD3403/SS928开发(二)环境搭建:从零到一构建高效开发环境的实战指南

本文详细介绍了海思SD3403/SS928开发板环境搭建的全流程,包括Ubuntu系统选择、基础配置、开发环境依赖安装、SDK工具链配置等关键步骤。通过实战经验分享,帮助开发者避免常见问题,快速构建高效开发环境,提升开发效率。

weixin_28717683的博客 278

C++中在一个cpp文件中引用另外一个cpp文件的方法

创建1个func2.cpp 通过include 引入func1.cpp 来使用func1里面的方法(如果有单独的头文件,比如func1.h 可以通过#include“func1.h”)C++中在一个cpp文件中引用另外一个cpp文件 可以通过导入cpp文件或者.h文件来实现,类似python中的import 导入。

小牧在一直在学习,在前进的道路上大家一起学习,进步。 7991

【大数据Java基础-Java基础01】环境搭建(一)Sublime Text3搭建Java编译环境(Windows系统)

1. 首先配置好Java环境变量 我的jdk版本是1.8.0_191,存放目录是C:\Program Files\Java,因此添加以下环境变量 (1)系统变量→新建 JAVA_HOME 变量,变量值为: C:\Program Files\Java\jdk1.8.0_191 (2)系统变量→找到 Path 变量→编辑,末尾加入: ;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin 如果Path变量末尾本身有“;”,则上述路径前面则不需要加“;” (3)系统变量→新建 CL

微信搜:import_bigdata,大数据领域硬核原创作者 546

图机器学习(2)——图的可视化

图结构可通过图形化方式直观呈现。节点通常用圆形表示,边则用连接线表示。然而当节点和边数量增加时,绘制清晰的图形表示可能会变得相当困难,这主要源于节点在二维坐标系中的布局问题。对于包含数百个节点的图,手动指定每个节点的坐标显然不切实际。在本节中,我们将介绍如何在不指定每个节点坐标的情况下绘制图形。我们将利用两种不同的解决方案:networkx 和 Gephi。

盼小辉丶的博客 8406

c++ 开发中利用yaml-cpp读写yaml配置文件

在程序员的开发生涯中,读写配置文件必不可少。 配置文件有利于我们灵活配置工程,解决大量重复劳动,也方便调试。 配置文件的格式有很多,最简单的有一行一行的文本,也有像 json、xml、protocol buffer 这样结构化的格式,当然也有 yaml 这种格式。 今天的博文介绍的是如何在 C++ 开发中利用 yaml-cpp 开源库读写 yaml 配置文件。 如果有 Python 开发经验的同学...

frank 的专栏 6万+

ESP32-C3入门教程 WiFi篇①——WiFi Scan 扫描附近AP无线热点 | 堵塞等待扫描结果,回调事件通知扫描结果

文章目录一、快速运行二、运行效果三、程序流畅四、关键函数4.1 扫描所有有效的AP4.2 获取上次扫描中找到的AP列表4.3 获取上次扫描中找到的AP数 一、快速运行 示例项目中,选择WiFi—>scan menuconfig配置ESP32C3-Specific—>Rec 0 芯片选择ESP32-C3(Built-in USB JTAG) 快速运行ESP-IDF Build, Flash and Monitor(左下角) 二、运行效果 三、程序流畅 esp_netif_init,初始

5413

【C++】11 Visual Studio 2019 C++安装matplotlib-cpp绘图

使用C++调用matplotlib-cpp绘图

记录专业模型开发、算法程序设计、软件学习笔记、生活日志。 9383

重回童年的经典系列☀️| 【坦克大战3D版】游戏制作+解析

带你重回童年的经典系列——坦克大战3D版制作,感兴趣的可以看看呀~

努力前行,总会成为自己心中的那道光 5万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: QT(C++)面试总结
下一篇: STL_day_2
我家瓜皮z47
博客等级 码龄9年 63粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值