《C++PrimerPlus》第13章 类继承

13.1 一个简单的基类

基类和派生类示例(球会会员管理)

头文件tabtenn1.h

#ifndef __TABTENN1_H__
#define __TABTENN1_H__#include <iostream>
#include <string>using namespace std;class TableTennisPlayer
{private:string firstname; string lastname;bool hasTable; // 是否有球桌public:TableTennisPlayer(const string &fn = "none", const string &ln = "none", bool ht = false);void Name() const;bool HasTable() const{return hasTable;}void ResetTable(bool v){hasTable = v;}
};class RatedPlayer : public TableTennisPlayer // 派生类
{
private:unsigned int rating; // 比分
public:RatedPlayer(unsigned int r = 0, const string &fn = "none", const string &ln = "none", bool ht = false); // 构造函数RatedPlayer(unsigned int r, const TableTennisPlayer &tp); // 构造函数unsigned int Rating() const { return rating; } // 显示比分void ResetRating(unsigned int r) { rating = r; } // 复位比分
};#endif

源代码main.cpp

#include <iostream>
#include "tabtenn1.h"using namespace std;int main(void)
{RatedPlayer rplay1(1140, "Mallory", "Duck", false);rplay1.Name(); // 派生类使用基类的成员函数if (rplay1.HasTable())cout << ": has a table." << endl;elsecout << ": hasn't a table." << endl;rplay1.Name();cout << ": Rating: " << rplay1.Rating() << endl;TableTennisPlayer player1("Tara", "Boomdea", false);RatedPlayer rplayer2(1212, player1); // 调用第二个构造函数cout << "Name: ";rplayer2.Name();cout << ": Rating : " << rplayer2.Rating() << endl;return 0;
}

源代码tabtenn1.cpp

#include "tabtenn1.h"TableTennisPlayer::TableTennisPlayer(const string &fn, const string &ln, bool ht)
{firstname = fn;lastname = ln;hasTable = ht;
}void TableTennisPlayer::Name() const
{cout << lastname << ", " << firstname;
}RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht) : TableTennisPlayer(fn, ln, ht) {rating = r;
}RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer &tp) : TableTennisPlayer(tp) { // 调用基类的复制构造函数(隐式调用,编译器自动生成)rating = r;
}

13.2 继承:is-a关系

13.3 多态公有继承

多态公有继承示例(银行的两类账户)

头文件brass.h

#ifndef __BRASS_H__
#define __BRASS_H__#include <iostream>
#include <string>
using namespace std;class Brass {
private:string fullName; // 客户姓名long acctNum; // 账号double balance; // 当前结余
public:Brass(const string &s = "Null", long an = -1,double bal = 0.0); // 创建账户(构造函数)void Deposit(double amt); // 存款virtual void Withdraw(double amt); // 取款(虚)double Balance() const; // 显示当前余额virtual void ViewAcct() const; // 显示账户信息(虚)virtual ~Brass(){}
};class BrassPlus : public Brass { // 派生类
private:double maxLoan; // 透支上限double rate; // 透支利率double owesBank; // 当前的透支总额
public:BrassPlus(const string &s = "Null", long an = -1, double bal = 0.0,double ml = 500.0, double rate = 0.11125); // 构造函数BrassPlus(const Brass &ba, double ml = 500.0, double rate = 0.11125); // 构造函数virtual void ViewAcct() const; // 显示账户信息(多态)(虚)virtual void Withdraw(double amt); // 取款(虚)void ResetMax(double m) { maxLoan = m; } // 修改存款最大值void ResetRate(double r) { rate = r; } // 修改利率void ResetOwes() { owesBank = 0.0; } // 将透支总额复位为0
};#endif // !__BRASS_H__

源代码main.cpp

#include "brass.h"const int CLIENTS = 3;int main()
{Brass Rick("Rick", 123456, 4000.0);BrassPlus Jack("Jack", 654321, 3000.0);Rick.ViewAcct();cout << endl;Jack.ViewAcct();cout << endl;cout << "Depositing $1000 into the Jack Account." << endl;Jack.Deposit(1000);Jack.ViewAcct();cout << endl;cout << "Withdraw $4200 from the Rick Account." << endl;Rick.Withdraw(4200);Rick.ViewAcct();cout << endl;cout << "Withdraw $4200 from the Jack Account." << endl;Jack.Withdraw(4200);Jack.ViewAcct();cout << endl;/*******************使用引用或指针************************/// 使用基类指针:可以指向基类对象,也可以指向派生类对象Brass *p_clients[CLIENTS]; //基类的指针数组,每个元素都是一个基类的指针string temp;long tempnum;double tempbal;int kind;for (int i = 0; i < CLIENTS; i++) {cout << "Enter the client's name: ";getline(cin, temp);cout << "Enter client's account number: ";cin >> tempnum;cout << "Enter opening balance: $";cin >> tempbal;cout << "Enter 1 for Brass Account or 2 for BrassPlus Account: ";while (cin >> kind && (kind != 1 && kind != 2))cout << "Please enter either 1 or 2: ";if (kind == 1)p_clients[i] = new Brass(temp, tempnum, tempbal); // 对类使用new,将会调用相应的构造函数else {double tmax, trate;cout << "Enter the overdraft limit: $";cin >> tmax;cout << "Enter the rate: ";cin >> trate;p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);}while (cin.get() != '\n'); // 消耗掉回车}cout << endl;for (int i = 0; i < CLIENTS; i++) {// 虚方法,根据指针引用的对象来确定用哪种方法p_clients[i]->ViewAcct(); // 注意通过指针调用,用的是->cout << endl;}for (int i = 0; i < CLIENTS; i++) {// 必须要有虚析构函数,根据指针引用的对象来确定用哪种析构函数delete p_clients[i]; // 有new就有delete!}return 0;
}

源代码brass.cpp

#include "brass.h"Brass::Brass(const string &s, long an, double bal) {fullName = s;acctNum = an;balance = bal;
}void Brass::Deposit(double amt) {if (amt < 0)cout << "Negative value is not allowed!" << endl;elsebalance += amt;
}void Brass::Withdraw(double amt) {if (amt < 0)cout << "Negative value is not allowed!" << endl;else if (amt <= balance)balance -= amt;elsecout << "Withdraw amount exceeded your balance!" << endl;
}double Brass::Balance() const {return balance;
}void Brass::ViewAcct() const {cout << "Client: " << fullName << endl;cout << "Account number: " << acctNum << endl;cout << "Balance: $" << balance << endl;
}BrassPlus::BrassPlus(const string &s, long an, double bal, double ml,double r) : Brass(s, an, bal) {maxLoan = ml;rate = r;owesBank = 0.0;
}BrassPlus::BrassPlus(const Brass &ba, double ml, double r) : Brass(ba) {maxLoan = ml;rate = r;owesBank = 0.0;
}void BrassPlus::ViewAcct() const { // 定义的时候不需要加virtualBrass::ViewAcct(); // 派生类调用基类方法cout << "Maxium load: $" << maxLoan << endl;cout << "Loan Rate: " << rate << endl;cout << "Owed to bank: $" << owesBank << endl;
}void BrassPlus::Withdraw(double amt) {double bal = Balance();if (amt <= bal) // 取的钱小于余额Brass::Withdraw(amt);else if (amt <= bal + maxLoan - owesBank) { // 透支取钱double advance = amt - bal; // 透支的钱owesBank = advance * (1.0 + rate); // 欠银行的钱(加上利息)cout << "Bank Advance: $" << advance << endl;cout << "Finance charge: $" << advance * rate << endl;Deposit(advance); // 存钱Brass::Withdraw(amt); // 取钱}else // 透支也不够取cout << "Credit limit exceeded!" << endl;}

13.4 静态联编和动态联编

13.5 访问控制:protected

13.6 抽象基类

抽象类示例(银行的两类账户)

头文件acctabc.h

#ifndef __ACCTABC_H__
#define __ACCTABC_H__#include <iostream>
#include <string>
using namespace std;class AcctABC {
private:string fullName;long acctNum;double balance;
protected:const string &FullName() const { return fullName; } // 返回客户姓名long AcctNum() const { return acctNum; } // 返回客户账号
public:AcctABC(const string &s = "Null", long an = -1,double bal = 0.0); // 构造函数void Deposit(double amt); // 存款virtual void Withdraw(double amt) = 0; // 取款(纯虚函数)double Balance() const { return balance; } // 显示当前余额virtual void ViewAcct() const = 0; // 显示账户信息(纯虚函数)virtual ~AcctABC(){} // 析构函数(虚函数)
};class Brass : public AcctABC{
public:Brass(const string &s = "Null", long an = -1,double bal = 0.0) : AcctABC(s, an, bal) {} // 创建账户(构造函数)virtual void Withdraw(double amt); // 取款(虚)virtual void ViewAcct() const; // 显示账户信息(虚)virtual ~Brass(){}
};class BrassPlus : public AcctABC{ // 派生类
private:double maxLoan; // 透支上限double rate; // 透支利率double owesBank; // 当前的透支总额
public:BrassPlus(const string &s = "Null", long an = -1, double bal = 0.0,double ml = 500.0, double rate = 0.11125); // 构造函数BrassPlus(const Brass &ba, double ml = 500.0, double rate = 0.11125); // 构造函数virtual void ViewAcct() const; // 显示账户信息(多态)(虚)virtual void Withdraw(double amt); // 取款(虚)void ResetMax(double m) { maxLoan = m; } // 修改存款最大值void ResetRate(double r) { rate = r; } // 修改利率void ResetOwes() { owesBank = 0.0; } // 将透支总额复位为0
};#endif // !__BRASS_H__

源代码main.cpp

#include "acctabc.h"const int CLIENTS = 3;int main()
{AcctABC *p_clients[CLIENTS]; //基类的指针数组,每个元素都是一个基类的指针string temp;long tempnum;double tempbal;int kind;for (int i = 0; i < CLIENTS; i++) {cout << "Enter the client's name: ";getline(cin, temp);cout << "Enter client's account number: ";cin >> tempnum;cout << "Enter opening balance: $";cin >> tempbal;cout << "Enter 1 for Brass Account or 2 for BrassPlus Account: ";while (cin >> kind && (kind != 1 && kind != 2))cout << "Please enter either 1 or 2: ";if (kind == 1)p_clients[i] = new Brass(temp, tempnum, tempbal); // 对类使用new,将会调用相应的构造函数else {double tmax, trate;cout << "Enter the overdraft limit: $";cin >> tmax;cout << "Enter the rate: ";cin >> trate;p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);}while (cin.get() != '\n'); // 消耗掉回车}cout << endl;for (int i = 0; i < CLIENTS; i++) {// 虚方法,根据指针引用的对象来确定用哪种方法p_clients[i]->ViewAcct(); // 注意通过指针调用,用的是->cout << endl;}for (int i = 0; i < CLIENTS; i++) {// 必须要有虚析构函数,根据指针引用的对象来确定用哪种析构函数delete p_clients[i]; // 有new就有delete!}return 0;
}

源代码acctabc.cpp

#include "acctABC.h"AcctABC::AcctABC(const string &s, long an, double bal) {fullName = s;acctNum = an;balance = bal;
}void AcctABC::Deposit(double amt) {if (amt < 0)cout << "Negative value is not allowed!" << endl;elsebalance += amt;
}void AcctABC::Withdraw(double amt) {balance -= amt;
}void Brass::Withdraw(double amt) {if (amt < 0)cout << "Negative value is not allowed!" << endl;else if (amt <= Balance())AcctABC::Withdraw(amt);elsecout << "Withdraw amount exceeded your balance!" << endl;
}void Brass::ViewAcct() const {cout << "Client: " << FullName() << endl;cout << "Account number: " << AcctNum() << endl;cout << "Balance: $" << Balance() << endl;
}BrassPlus::BrassPlus(const string &s, long an, double bal, double ml,double r) : AcctABC(s, an, bal) {maxLoan = ml;rate = r;owesBank = 0.0;
}BrassPlus::BrassPlus(const Brass &ba, double ml, double r) : AcctABC(ba) {maxLoan = ml;rate = r;owesBank = 0.0;
}void BrassPlus::ViewAcct() const { // 定义的时候不需要加virtualcout << "Client: " << FullName() << endl;cout << "Account number: " << AcctNum() << endl;cout << "Balance: $" << Balance() << endl;cout << "Maxium load: $" << maxLoan << endl;cout << "Loan Rate: " << rate << endl;cout << "Owed to bank: $" << owesBank << endl;
}void BrassPlus::Withdraw(double amt) {double bal = Balance();if (amt <= bal) // 取的钱小于余额AcctABC::Withdraw(amt);else if (amt <= bal + maxLoan - owesBank) { // 透支取钱double advance = amt - bal; // 透支的钱owesBank = advance * (1.0 + rate); // 欠银行的钱(加上利息)cout << "Bank Advance: $" << advance << endl;cout << "Finance charge: $" << advance * rate << endl;Deposit(advance); // 存钱AcctABC::Withdraw(amt); // 取钱}else // 透支也不够取cout << "Credit limit exceeded!" << endl;}

13.7 继承和动态内存分配

继承和动态内存分配示例(派生类使用或不使用new)

头文件dma.h

#ifndef __DMA_H___
#define __DMA_H___#include <iostream>
using namespace std;class baseDMA {
private:char *label;int rating;
public:baseDMA(const char *l = "null", int r = 0); // 构造函数baseDMA(const baseDMA &rs); // 复制构造函数virtual ~baseDMA(); // 析构函数(虚)baseDMA &operator=(const baseDMA &s); // 重载=运算符friend ostream &operator<<(ostream &os, const baseDMA &rs); // 重载<<运算符
};class lacksDMA : public baseDMA {
private:enum { COL_LEN = 40 };char color[COL_LEN];
public:lacksDMA(const char *l = "null", int r = 0, const char *c = "blank"); // 构造函数lacksDMA(const baseDMA &rs, const char *c = "blank");friend ostream &operator<<(ostream &os, const lacksDMA &rs);
};class hasDMA : public baseDMA {
private:char *style;
public:hasDMA(const char *l = "null", int r = 0, const char *s = "none");hasDMA(const baseDMA &rs, const char *s);hasDMA(const hasDMA &hs); // 复制构造函数~hasDMA(); // 析构函数hasDMA &operator=(const hasDMA &hs); // 重载=运算符friend ostream &operator<<(ostream &os, const hasDMA &rs); // 重载<<运算符
};#endif

源代码main.cpp

#include "dma.h"int main()
{baseDMA shirt("Protabelly", 8);cout << "Displaying baseDMA object: " << endl;cout << shirt;cout << "-----------------------------------" << endl;lacksDMA ballon("Blimpo", 4, "red");cout << "Displaying lacksDMA object: " << endl;cout << ballon;cout << "-----------------------------------" << endl;lacksDMA ballon2(ballon); // 调用默认复制构造函数cout << ballon2;cout << "-----------------------------------" << endl;hasDMA map("Keys", 5, "Mercator");cout << "Displaying hasDMA object: " << endl;cout << map << endl;cout << "-----------------------------------" << endl;hasDMA map2 = map; // 使用复制构造函数cout << map2 << endl;cout << "-----------------------------------" << endl;hasDMA map3; map3 = map; // 使用重载赋值运算符cout << map3 << endl;return 0;
}

源代码dma.cpp

#include "dma.h"
#include <cstring>baseDMA::baseDMA(const char *l, int r) {label = new char[strlen(l) + 1];strcpy_s(label, strlen(l) + 1, l);rating = r;
}baseDMA::baseDMA(const baseDMA &rs) {label = new char[strlen(rs.label) + 1];strcpy_s(label, strlen(rs.label) + 1, rs.label);rating = rs.rating;
}baseDMA::~baseDMA() {delete[] label;
}baseDMA &baseDMA::operator=(const baseDMA &rs) {if (this == &rs) return *this;delete[] label;label = new char[strlen(rs.label) + 1];strcpy_s(label, strlen(rs.label) + 1, rs.label);rating = rs.rating;return *this;
}ostream &operator<<(ostream &os, const baseDMA &rs) {os << "Label: " << rs.label << endl;os << "Rating: " << rs.rating << endl;return os;
}lacksDMA::lacksDMA(const char *l, int r, const char *c) : baseDMA(l, r) {strncpy_s(color, COL_LEN, c, strlen(c)); // 注意strncpy和strncpy_s的区别
}lacksDMA::lacksDMA(const baseDMA &rs, const char *c) : baseDMA(rs) {strncpy_s(color, COL_LEN, c, strlen(c));
}ostream &operator<<(ostream &os, const lacksDMA &ls) {os << (const baseDMA &)ls; // 强制类型转换,使用基类的运算符输出基类的信息os << "Color: " << ls.color << endl;return os;
}hasDMA::hasDMA(const char *l, int r, const char *s) : baseDMA(l, r) {style = new char[strlen(s) + 1];strcpy_s(style, strlen(s) + 1, s);
}hasDMA::hasDMA(const baseDMA &rs, const char *s) : baseDMA(rs) {style = new char[strlen(s) + 1];strcpy_s(style, strlen(s) + 1, s);
}hasDMA::hasDMA(const hasDMA &hs) : baseDMA(hs) {cout << "Copy construct function." << endl; // 标记一下复制构造函数被使用style = new char[strlen(hs.style) + 1];strcpy_s(style, strlen(hs.style) + 1, hs.style);
}hasDMA::~hasDMA() {delete[] style;
}hasDMA &hasDMA::operator=(const hasDMA &hs) {cout << "operator function." << endl; // 标记重载赋值运算符被使用if (this == &hs) return *this;// 基类的重载运算符的函数表示法,传递给this指针// 这里不能写出this,否则会无限递归baseDMA::operator=(hs);delete[] style;style = new char[strlen(hs.style) + 1];strcpy_s(style, strlen(hs.style) + 1, hs.style);return *this;
}ostream &operator<<(ostream &os, const hasDMA &hs) {os << (const baseDMA &)hs; // 强制类型转换,使用基类的运算符输出基类的信息os << "Style: " << hs.style << endl;return os;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/585686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RS-485 RS-232 RS-422 区别和理解

RS-485&#xff0c;RS-232&#xff0c;RS-422区别和理解 目录概述需求&#xff1a; 设计思路实现思路分析1.概述2.区别 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a b…

【MySQL】数据库之存储过程(“SQL语句的脚本“)

目录 一、什么是存储过程&#xff1f; 二、存储过程的作用 三、如何创建、调用、查看、删除、修改存储过程 四、存储过程的参数&#xff08;输入参数&#xff0c;输出参数&#xff0c;输入输出参数&#xff09; 第一种&#xff1a;输入参数 第二种&#xff1a;输出参数 …

利用 IntelliJ IDEA 整合 GitHub 实现项目版本控制与协作管理

目录 前言1 设置GitHub登录账号2 将项目分享到GitHub3 IntelliJ IDEA 中导入Github项目4 往GitHub推送代码4.1 Commit Change&#xff08;提交到本地库&#xff09;4.2 Git -> Repository -> Push&#xff08;推送到远程库&#xff09; 5 拉取远程库代码到本地6 克隆远程…

Android MVC 写法

前言 Model&#xff1a;负责数据逻辑 View&#xff1a;负责视图逻辑 Controller&#xff1a;负责业务逻辑 持有关系&#xff1a; 1、View 持有 Controller 2、Controller 持有 Model 3、Model 持有 View 辅助工具&#xff1a;ViewBinding 执行流程&#xff1a;View >…

Ubuntu22.04系统安装软件、显卡驱动、cuda、cudnn、pytorch

Ubuntu22.04系统安装软件、显卡驱动、cuda、cudnn、pytorch 安装 Nvidia 显卡驱动安装 CUDA安装 cuDNN安装 VSCode安装 Anaconda 并更换源在虚拟环境中安装 GPU 版本的 PyTorchReference 这篇博文主要介绍的是 Ubuntu22.04 系统中软件、显卡驱动、cuda、cudnn、pytorch 等软件和…

树莓派摄像头使用python获取摄像头内容将图片上传到百度云识别文字并将识别结果返回

要使用树莓派摄像头通过Python获取图像并将其上传到百度云进行文字识别&#xff0c;然后将识别结果打印到串口&#xff0c;可以按照以下步骤进行操作&#xff1a; 确保您已经在百度云的控制台上创建了一个文字识别应用&#xff0c;并获得了API Key和Secret Key。 在树莓派上安…

华为OD机试真题-最小矩阵宽度-2023年OD统一考试(C卷

题目描述&#xff1a; 给定一个矩阵&#xff0c;包含N*M个整数&#xff0c;和一个包含K个整数的数组。 现在要求在这个矩阵中找一个宽度最小的子矩阵&#xff0c;要求子矩阵包含数组中所有的整数。 输入描述&#xff1a; 第一行输入两个正整数N&#xff0c;M&#xff0c;表…

MySQLclient使用笔记

使用libmysqlclient库时&#xff0c;遇到的问题和性能分析总结 需要8.0.16之后版本才支持异步 一、测试情况 测试环境 虚拟机&#xff1a;Ubuntu16.04 CPU&#xff1a;4核 内存&#xff1a;8G 数据库表数据量&#xff1a;3万条 libmysqlclient&#xff1a;8.0.25 测试量 执行1万…

STM32CubeMX教程8 TIM 通用定时器 - 输出比较

目录 1、准备材料 2、实验目标 3、实验流程 3.0、前提知识 3.1、CubeMX相关配置 3.1.1、时钟树配置 3.1.2、外设参数配置 3.1.3、外设中断配置 3.2、生成代码 3.2.1、外设初始化函数调用流程 3.2.2、外设中断函数调用流程 3.2.3、添加其他必要代码 4、常用函数 5…

使用Mindspore实现词袋模型思想

链接&#xff1a;词袋模型_百度百科 词袋模型模型下&#xff0c;像是句子或是文件这样的文字可以用一个袋子装着这些词的方式表现&#xff0c;这种表现方式不考虑文法以及词的顺序。最近词袋模型也被应用在电脑视觉领域。 词袋模型被广泛应用在文件分类&#xff0c;词出现的频…

轮廓检测与处理

轮廓检测 先将图像转换成二值 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度图 ret, thresh cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 变为二值&#xff0c;大于127置为255&#xff0c;小于100置为0.使用cv2.findContours(thresh, cv2.RETR_TREE, cv2.…

jvm实战之-常用jvm命令的使用

各命令的使用 JMAP 1、查看内存信息&#xff0c;对象实例数、对象占有大小 jmap -histo 进程号>./log.txt2、查看堆的配置信息和使用情况 jmap - heap 进程号3、将堆的快照信息dump下来&#xff0c;使用java自带的jvisualvm.exe打开分析 jmap -dump:formatb,filedump.h…

Elasticsearch:升级索引以使用 ELSER 最新的模型

在此 notebook 中&#xff0c;我们将看到有关如何使用 Reindex API 将索引升级到 ELSER 模型 .elser_model_2 的示例。 注意&#xff1a;或者&#xff0c;你也可以通过 update_by_query 来更新索引以使用 ELSER。 在本笔记本中&#xff0c;我们将看到使用 Reindex API 的示例。…

二叉树之堆的应用

目录 堆排序 思路详解 Ⅰ 建堆 Ⅱ 利用堆的删除思想来进行排序 功能接口 向上调整算法 向下调整算法 主函数 运行结果展示 TOP - K问题 思路详解 Ⅰ 用数据集合中前K个元素来建堆 Ⅱ 用剩余的N-K个元素依次与堆顶元素来比较&#xff0c;不满足则替换堆顶元素 功…

算法刷题:最大异或对(Trie树扩展)、食物链(并查集扩展)

目录 引言一、最大异或对&#xff08;Trie树扩展&#xff09;1.题目描述2.解题思路3.代码实现4.测试 二、食物链&#xff08;并查集扩展&#xff09;1.题目描述2.解题思路3.代码实现4.测试 引言 这两个扩展题能够让我们更加的熟悉Trie树和并查集的使用&#xff0c;这两道题可以…

C语言中的goto语句详解与使用方法

引言 虽然goto语句在现代编程实践中并不常见&#xff0c;但了解其基本用法仍然是有益的。本篇博客将为你详细介绍goto语句的使用方法&#xff0c;希望对你的学习有所帮助。 1. 什么是goto语句&#xff1f; goto是C语言中的一个关键字&#xff0c;用于实现无条件跳转。使用got…

MySQL:子查询

子查询 子查询是嵌套在较大查询中的 SQL 查询&#xff0c;也称内部查询或内部选择&#xff0c;包含子查询的语句也称为外部查询或外部选择。简单来说&#xff0c;子查询就是指将一个 select 查询&#xff08;子查询&#xff09;的结果作为另一个 SQL 语句&#xff08;主查询&a…

深入浅出理解Web认证:Session、Cookie与Token

在Web开发的世界中&#xff0c;理解Session、Session ID、Cookie和Token之间的区别至关重要。实际上&#xff0c;这些概念并不复杂&#xff0c;只需几句话就能澄清它们的核心区别。 首先&#xff0c;我们需要区分Session和Session ID。Session实际上是存储在服务器端的数据&am…

Leetcode的AC指南 —— 哈希法/双指针:15. 三数之和

摘要&#xff1a; Leetcode的AC指南 —— 15. 三数之和。题目介绍&#xff1a;给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且…

掌握numpy.einsum与torch.einsum:提升科学计算与深度学习中的运算效率和代码可读性

文章目录 一、前言二、Einstein求和记号简介1. 规则和表达能力2. 表示常见的数组和张量运算 三、numpy.einsum的应用与实践1. numpy.einsum的基础使用矩阵的迹矩阵乘法向量点积按元素相加求和 2. numpy.einsum的高级功能矩阵转置秩变换计算协方差矩阵广播乘法 四、torch.einsum…