This commit is contained in:
2026-02-13 23:38:38 +08:00
commit 0207414c50
551 changed files with 35558 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
# SDUT-离散数学-2024-计科2306恩师王举辉
此计不成,既有后来人。
欢迎sduter来进行讨论与指正。
# 感悟
这门课程就是为了后面的数据结构后学习的 主要还是以定义以及性质定理为主, 就是上课好好听bushi然后刚开始听可能不懂但是后来回过头看一看 欸 突然开窍了。嘿嘿嘿。
题目不是很难 但是就是定义以及性质的运用
# 章一
![1](C:\Users\33882\Desktop\离散数学\1.jpg)
![2](C:\Users\33882\Desktop\离散数学\2.jpg)
# 章二:谓词逻辑&章三:集合与关系
![3](C:\Users\33882\Desktop\离散数学\3.jpg)
![4](C:\Users\33882\Desktop\离散数学\4.jpg)
![5](C:\Users\33882\Desktop\离散数学\5.jpg)
![6](C:\Users\33882\Desktop\离散数学\6.jpg)
![8](C:\Users\33882\Desktop\离散数学\8.jpg)
# 章四:函数
![10](C:\Users\33882\Desktop\离散数学\10.jpg)
章五:代数系统
![11](C:\Users\33882\Desktop\离散数学\11.jpg)
![12](C:\Users\33882\Desktop\离散数学\12.jpg)
![13](C:\Users\33882\Desktop\离散数学\13.jpg)
![14](C:\Users\33882\Desktop\离散数学\14.jpg)
# 最后一章:图论
![15](C:\Users\33882\Desktop\离散数学\15.jpg)
![16](C:\Users\33882\Desktop\离散数学\16.jpg)
![17](C:\Users\33882\Desktop\离散数学\17.jpg)
![18](C:\Users\33882\Desktop\离散数学\18.jpg)
![19](C:\Users\33882\Desktop\离散数学\19.jpg)
![20](C:\Users\33882\Desktop\离散数学\20.jpg)
![21](C:\Users\33882\Desktop\离散数学\21.jpg)
![22](C:\Users\33882\Desktop\离散数学\22.jpg)
![7](C:\Users\33882\Desktop\离散数学\7.jpg)
![9](C:\Users\33882\Desktop\离散数学\9.jpg)

View File

@@ -0,0 +1,138 @@
# 范围
# 计算机网络各章节复习重点
## 第1章计算机网络基础
- **交换方式**
- 电路交换、报文交换、分组交换的特点及适用场景。
- **网络分类**
- 分类标准(如覆盖范围、拓扑结构等)。
- **体系结构**
- **OSI七层模型**(理论模型)与 **TCP/IP四层模型**(实际应用)的层次划分及各层作用。
- 五层模型(简化理解)的层次:物理层、数据链路层、网络层、运输层、应用层。
---
## 第2章物理层
- **关键概念**
- 信道极限容量(奈奎斯特定理、香农公式)的含义及计算。
- 码元、比特的区别;通过码元携带更多信息提高传输速率的方法。
- **复用技术**
- 频分复用FDM、时分复用TDM、统计时分复用STDM、波分复用WDM的工作原理。
- 课后练习题:涉及数据发送方、码元与比特的计算。
---
## 第3章数据链路层
- **基本概念**
- 链路、数据链路的定义;三个基本问题(封装成帧、透明传输、差错检测)。
- CRC校验码的计算需掌握课后习题
- **设备与协议**
- 适配器(网卡)的功能。
- CSMA/CD协议的工作原理以太网介质访问控制
- 集线器(物理层)与交换机(数据链路层)的区别;交换机的自学习机制及转发表建立过程。
- **VLAN**
- VLAN的类型如基于端口、MAC地址等及优点隔离广播域、提高安全性等
---
## 第4-5章网络层
- **IP地址与子网划分**
- 分类IP地址A/B/C/D/E类的判断无分类编址CIDR与子网掩码的作用。
- 子网划分固定长度子网、可变长子网VLSM子网号、地址范围、可用地址的计算需结合子网掩码
- **路由选择**
- 路由器转发分组的算法目的IP与子网掩码按位与运算得到网络号匹配转发表优先顺序主机路由 → 网络路由 → 默认路由)。
- 路由协议分类:
- 自治系统AS内部RIP、OSPF等。
- 自治系统间BGP。
- **特殊地址与技术**
- 专用地址(私有地址)的范围及特点(互联网路由器不转发)。
- 虚拟专用网VPN与网络地址转换NAT的应用场景及区别。
---
## 第6章运输层
- **协议对比**
- TCP与UDP的特点及区别连接性、可靠性、传输单位等
- 端口号的作用:区分不同应用进程。
- **TCP核心机制**
- 滑动窗口机制:发送窗口大小由接收窗口和拥塞窗口共同决定。
- 流量控制与拥塞控制的实现:调整窗口大小;拥塞控制算法(慢开始、拥塞避免、快重传、快恢复)。
- 三次握手建立连接、四次挥手释放连接的过程及原因。
- **UDP特点**
- 无连接、不可靠、面向报文,适用于实时数据传输(如视频流)。
---
## 第7章应用层
- **域名系统DNS**
- 四类服务器(根域名服务器、顶级域名服务器、权限域名服务器、本地域名服务器)的作用及域名解析过程。
- **万维网WWW**
- 解决的四个核心问题及对应技术HTTP协议、URL、HTML等
- **常见应用协议**
- 区分使用TCP如HTTP、FTP和UDP如DNS、DHCP的高层协议。
---
## 第8章网络安全
- **安全威胁**
- 被动攻击(窃听、截获)与主动攻击(篡改、伪造)的区别。
- **加密技术**
- 对称加密如DES与非对称加密如RSA的模型及应用场景。
- **数字签名与保密**
- 数字签名的作用(鉴别发送者);结合加密实现保密的方法(如用接收方公钥加密)。
- **安全设备**
- 防火墙的功能入侵检测系统IDS的作用。
---
## 其他重点
- **实验与作业**
- 实验报告需手写并扫描上传重视课后习题子网划分、CRC计算、路由转发算法
- 平时成绩构成:作业、实验、课堂表现。
- **复习建议**
- 重点掌握PPT内容及教材指定章节如分组转发算法见143页TCP/UDP特点见216/219页
# 物理层
# 数据链路层
## CSMA/CD
<img src="F:\记录\image-20250601215956519.png" alt="image-20250601215956519" style="zoom:33%;" />
ANS:B
<img src="F:\记录\image-20250601220104712.png" alt="image-20250601220104712" style="zoom:33%;" />
![image-20250601220355280](F:\记录\image-20250601220355280.png)
![image-20250601220748017](F:\记录\image-20250601220748017.png)
## 交换机的自学习功能
![image-20250606171956311](F:\记录\image-20250606171956311.png)
# 网络层
![image-20250606214847373](F:\记录\image-20250606214847373.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -0,0 +1,259 @@
```sql
-- 增删改
INSERT INTO products (maker, model, type)
VALUES ('I', '3008', 'printer');
INSERT INTO sales (customer_id, model, quantity, day, paid, type_of_payment)
VALUES ('1112223333', '3008', 2, '2024-01-01', 200, 'cash');
INSERT INTO customers (customer_id, firstname, lastname, city, address, email)
VALUES ('1112223333', 'Lisa', 'Smith', 'Dublin', '5 Main St.', 'lisa@example.com');
-- 更新
UPDATE pcs
SET price = 2200
WHERE model = '1001';
UPDATE sales
SET type_of_payment = 'visa credit'
WHERE customer_id = '1122334455' AND model = '2010';
UPDATE customers
SET email = 'norah.jones@yahoo.com'
WHERE customer_id = '9999999999';
-- 删除
DELETE FROM printers
WHERE model = '3006';
DELETE FROM sales
WHERE day = '2013-12-17';
DELETE FROM customers
WHERE customer_id = '1231231231';
-- 完成数据库新用户创建、
CREATE USER `zds`
-- 授权访问数据库、
GRANT SELECT, UPDATE, INSERT ON TABLE sales TO zds;
-- 授权用户传递权限with grant option
GRANT SELECT ON sdut.sales TO zds WITH GRANT OPTION
-- 收回用户的sales表更新权限
REVOKE UPDATE ON sdut.sales FROM zds;
-- 收回所有权限(彻底回收)
REVOKE ALL PRIVILEGES ON sdut.sales FROM zds
-- 删除创建的用户
DROP USER zds;
-- 触发器
-- 1
CREATE TABLE pcprice_log (
log_id INT AUTO_INCREMENT PRIMARY KEY,
model VARCHAR(10) NOT NULL,
old_price DECIMAL(10,2) NOT NULL,
new_price DECIMAL(10,2) NOT NULL
);
CREATE TRIGGER insert_pcpricelog_values_when_pc_price_changed
AFTER UPDATE ON pcs
FOR EACH ROW
BEGIN
IF OLD.price != NEW.price THEN
INSERT INTO pcprice_log (model, old_price, new_price)
VALUES (OLD.model, OLD.price, NEW.price);
END IF;
END;
-- 测试
-- INSERT INTO pcs (model, price, speed, ram, hd )
-- VALUES ('1005', 200, 3.0, 8, 512);
-- UPDATE pcs set price=22 WHERE model=1005
-- 2定义AFTER行级触发器当删除顾客表Customer中的一个顾客信息后同时删除购买信息表Sales中该顾客的所有购买记录
CREATE TRIGGER deleteCustomer
after DELETE on customers
for each row
BEGIN
DELETE FROM sales
WHERE customer_id = OLD.customer_id;
END
-- -- 测试
-- DELETE FROM customers WHERE customer_id=9999999999
-- 3需要对在表上进行DML操作的用户进行安全检查看是否具有合适的特权
-- 权限表存储用户可执行的DML权限JSON数组格式如["insert","update"]
CREATE TABLE IF NOT EXISTS userPrivilege (
id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(100) NOT NULL UNIQUE COMMENT '用户名格式user@host如root@localhost匹配CURRENT_USER()',
privilege JSON NOT NULL COMMENT '权限列表JSON数组值为"insert"/"update"/"delete"(统一小写)',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '权限创建时间'
);
-- 插入测试数据给用户zds@localhost分配INSERT/UPDATE权限不给DELETE权限
INSERT INTO userPrivilege (user_name, privilege)
VALUES ('zds@localhost', '["insert", "update"]');
-- 权限表存储用户可执行的DML权限JSON数组格式如["insert","update"]
CREATE TABLE IF NOT EXISTS userPrivilege (
id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(100) NOT NULL UNIQUE COMMENT '用户名格式user@host如root@localhost匹配CURRENT_USER()',
privilege JSON NOT NULL COMMENT '权限列表JSON数组值为"insert"/"update"/"delete"(统一小写)',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '权限创建时间'
);
-- 插入测试数据给用户zds@localhost分配INSERT/UPDATE权限不给DELETE权限
INSERT INTO userPrivilege (user_name, privilege)
VALUES ('zds@localhost', '["insert", "update"]');
DELIMITER //
CREATE TRIGGER trg_check_update_priv
BEFORE UPDATE ON customers -- 同样可替换为目标表
FOR EACH ROW
BEGIN
DECLARE user_priv JSON;
DECLARE has_update INT DEFAULT 0;
DECLARE curr_user VARCHAR(100) DEFAULT CURRENT_USER();
-- 查询当前用户权限
SELECT privilege INTO user_priv
FROM userPrivilege
WHERE user_name = curr_user;
-- 判断是否有"update"权限
IF user_priv IS NOT NULL THEN
SET has_update = JSON_CONTAINS(user_priv, '"update"');
END IF;
-- 无权限抛错
IF has_update = 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = CONCAT('安全检查失败:用户 [', curr_user, '] 无 ', TABLE_NAME, ' 表的 UPDATE 权限');
END IF;
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER trg_check_delete_priv
BEFORE DELETE ON customers -- 同样可替换为目标表
FOR EACH ROW
BEGIN
DECLARE user_priv JSON;
DECLARE has_delete INT DEFAULT 0;
DECLARE curr_user VARCHAR(100) DEFAULT CURRENT_USER();
-- 查询当前用户权限
SELECT privilege INTO user_priv
FROM userPrivilege
WHERE user_name = curr_user;
-- 判断是否有"delete"权限
IF user_priv IS NOT NULL THEN
SET has_delete = JSON_CONTAINS(user_priv, '"delete"');
END IF;
-- 无权限抛错
IF has_delete = 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = CONCAT('安全检查失败:用户 [', curr_user, '] 无 ', TABLE_NAME, ' 表的 DELETE 权限');
END IF;
END //
DELIMITER ;
-- 4如果某个特定客户ID的购买记录从销售表中删除后则从客户表中删除该客户。
CREATE TRIGGER deleteCustomer_by4
AFTER DELETE on sales
for each row
BEGIN
DELETE FROM customers
WHERE customer_id = OLD.customer_id;
END
CREATE TRIGGER discount AFTER INSERT ON sales FOR EACH ROW
BEGIN
DECLARE
sum_paid DECIMAL ( 12, 2 );
DECLARE
discount DECIMAL ( 5, 2 );
SELECT
sum( paid ) INTO sum_paid
FROM
sales
WHERE
customer_id = NEW.customer_id;
SELECT
discount INTO discount
FROM
customers
WHERE
customer_id = NEW.customer_id;
IF
SUM_paid > 10000
AND discount < 10.00 THEN
UPDATE customers
SET discount = 10.00
WHERE
customer_id = NEW.customer_id;
END IF;
END
-- 6在客户中添加一个新的"AllPaid"栏,如果插入或更新或删除一个销售元组,那么修改该客户的"AllPaid"的值
ALTER TABLE customers
ADD COLUMN AllPaid DECIMAL(12,2) NOT NULL DEFAULT 0.00
CREATE TRIGGER insert_value_customer
AFTER INSERT on customers
for each ROW
BEGIN
UPDATE customers
set AllPaid =(
SELECT SUM(paid) FROM sales
WHERE customer_id = NEW.customer_id
)
WHERE customer_id = NEW.customer_id;
END
CREATE TRIGGER UPDATE_value_customer
AFTER UPDATE on customers
for each ROW
BEGIN
UPDATE customers
set AllPaid =(
SELECT SUM(paid) FROM sales
WHERE customer_id = NEW.customer_id
)
WHERE customer_id = NEW.customer_id;
END
CREATE TRIGGER DELETE_value_customer
AFTER DELETE on customers
for each ROW
BEGIN
UPDATE customers
set AllPaid =(
SELECT SUM(paid) FROM sales
WHERE customer_id = old.customer_id
)
WHERE customer_id = old.customer_id;
END
-- 测试
```

View File

@@ -0,0 +1,96 @@
CREATE PROCEDURE RateModel ( IN cid VARCHAR ( 20 ), IN m VARCHAR ( 20 ), IN r INT ) BEGIN-- 1. 插入新评分记录
INSERT INTO ratings ( customer_id, model, rating_time, rating )
VALUES
( cid, m, NOW( ), r ) -- 2. 更新 Products 表的总评分和评分次数
INSERT IGNORE INTO Products ( total_rating, number_of_ratings )
VALUES
( 0, 0 );-- 3. 计算该型号的最新总评分和评分次数
UPDATE products
SET total_rating = ( SELECT COALESCE( SUM( rating ), 0 ) FROM Ratings WHERE model = m ),
number_of_ratings = ( SELECT COUNT( * ) FROM Ratings WHERE model = m )
WHERE
model = m;
END --
-- 2
CREATE PROCEDURE DeleteRating ( IN cid ( 10 ), IN m ( 10 ), ) BEGIN
CALL RateModel ( p_customer_id, p_model, NULL );
END -- 3
CREATE PROCEDURE CleanRatings ( INT cid ( 10 ) INT m ( 10 ) ) BEGIN
DELETE
FROM
Rating
WHERE
customer_id = cid
AND model = m
AND rating_time < (
SELECT
max_time
FROM
( SELECT MAX( r2.rating_time ) AS max_time FROM Ratings AS r2 WHERE r2.customer_id = p_customer_id AND r2.model = p_model ) AS t
);
END;
CALL RateModel ( '1122334455', '1001', 3 );
CALL RateModel ( '1122334455', '1001', 2 );
CALL RateModel ( '9999999999', '1001', 5 );
CALL RateModel ( '1122334455', '1001', NULL );
CALL RateModel ( '9999999999', '1001', 4 );
CALL RateModel ( '9999999999', '1001', NULL );
CALL RateModel ( '1122334455', '1001', 2 );
CALL CleanRatings ( '9999999999', '1001' );
CALL CleanRatings ( '1122334455', '1001' );
-- 3
CREATE VIEW AverageRatings(model, average_rating)
AS
SELECT
model,
COALESCE(SUM(rating) / COUNT(*), 0) AS average_rating
FROM Ratings
GROUP BY model
HAVING COUNT(*) > 0; -- 仅包含至少有1次评分的型号
-- 3.b
DELIMITER //
CREATE FUNCTION BestModel()
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
DECLARE max_avg FLOAT;
DECLARE best_model VARCHAR(20);
-- 步骤1获取最高平均评分
SELECT MAX(average_rating) INTO max_avg FROM AverageRatings;
-- 步骤2若无评分返回NULL
IF max_avg IS NULL THEN
RETURN NULL;
END IF;
-- 步骤3获取平均评分最高的所有型号选择最新非空评分的型号
SELECT model INTO best_model
FROM (
-- 子查询:获取平均评分最高的型号,及其最新非空评分时间
SELECT
ar.model,
MAX(CASE WHEN r.rating IS NOT NULL THEN r.rating_time ELSE NULL END) AS latest_non_null_time
FROM AverageRatings ar
JOIN Ratings r ON ar.model = r.model
WHERE ar.average_rating = max_avg
GROUP BY ar.model
ORDER BY latest_non_null_time DESC -- 按最新非空评分时间降序
LIMIT 1 -- 取最新的一个
) AS temp;
RETURN best_model;
END //
DELIMITER ;
-- 3.c

View File

@@ -0,0 +1,592 @@
# C++ Key Topics Summary for Final Review (C++ 知识点期末复习总结
## Lecture 1: Introduction to C++ 第1讲C++简介)
**Key Concepts 主要知识点:**
- **Machine Language机器语言** The most basic programming language, consisting of binary code (0和1) directly executed by hardware. Machine code is **machine-dependent与硬件相关**; a program written for one type of CPU wont run on another.
- **Assembly Language汇编语言** Uses short English-like **mnemonics助记符** to represent machine instructions. Requires an **assembler汇编器** to translate into machine code. Assembly is easier to read than binary but still specific to a CPU architecture.
- **High-Level Language高级语言** A programming language with English-like syntax and math-like notation. Examples: C++, Java. High-level code is portable and must be converted to machine code by a **compiler编译器** or run by an **interpreter解释器**. C++ is compiled into machine code (可编译成机器码执行), whereas Java is compiled to bytecode and run on the Java Virtual Machine (运行于JVM).
- **Phases of C++ Program CompilationC++程序的编译阶段)** C++ code undergoes several steps: **preprocessing预处理**, **compiling编译**, **linking连接**, and **loading载入**. The **preprocessor预处理程序** handles directives (like `#include`) before compilation. The **compiler编译器** translates source code to object code (machine instructions). The **linker连接器** combines your object code with libraries to produce an executable. The **loader加载程序** then loads the executable into memory for execution.
- **Object-Oriented Programming (OOP, 面向对象编程)** C++ supports OOP, which involves organizing software as collections of **classes** and **objects对象**. It emphasizes concepts like **encapsulation封装**, **inheritance继承**, and **polymorphism多态**. (Java is also OOP; C++ and Java share OOP concepts, but C++ allows lower-level memory control.)
**After-class Exercises 课后练习:**
1. **填空题:** 本章讨论的三种语言类型是 ***\**\*、\*\**\*** 和 ______。【提示】机器语言machine language、汇编语言assembly language和高级语言high-level language
2. **填空题:** 在C++系统中______ 程序在编译器开始翻译之前执行。【提示】预处理程序preprocessor
3. **填空题:** ______ 程序将编译器的输出与各种库函数结合起来生成可执行程序。【提示】连接器linker
4. **填空题:** ______ 程序将可执行程序从磁盘传送到内存中准备运行。【提示】加载程序loader
*Answers 答案:* 1) 机器语言, 汇编语言, 高级语言; 2) **预处理**程序; 3) **连接**程序; 4) **加载**程序。每个阶段各司其职,共同完成从源代码到可执行代码的转换。
## Lecture 2: Basic Syntax and Printing 第2讲C++基本语法与打印)
**Key Concepts 主要知识点:**
- **Comments注释** Non-executing text used to document code. `//` begins a **single-line comment单行注释**, and `/* ... */` encloses a **multi-line comment多行注释**. Comments improve readability and are ignored by the compiler (编译时会被忽略). (Java uses the same comment styles.)
- **Preprocessor Directive预处理指令** Lines beginning with `#` (like `#include <iostream>`) are processed by the preprocessor **before** compilation. For example, `#include <iostream>` inserts the declarations for input/output streams (输入输出流库) so we can use `std::cout` and `std::cin`. In C++, `<iostream>` is analogous to Javas `java.io` package, but C++ uses include files instead of import statements.
- **`main` Function主函数** The entry point of a C++ program. Defined as `int main()` typically. The keyword **`int`** indicates main returns an integer status code to the system. In C++, `main` can be outside any class (不属于任何类), whereas in Java the entry point is a `public static void main` method within a class.
- **Statements and Semicolon语句和分号** A **statement语句** is an instruction terminated by a semicolon `;`. C++ is a free-form language: you can use **whitespace空白字符** (spaces, tabs, newlines) to format code for readability; extra whitespace is generally ignored by the compiler. Each statement must end with `;`
- **Output with `std::cout`使用cout输出** Use `std::cout << "text";` to print to the console. The `<<` is the **stream insertion operator流插入运算符**, sending data to the output stream.
- **Input with `std::cin`使用cin输入** `std::cin` is the standard input stream (对应键盘输入). Using the extraction operator `>>`, as in `std::cin >> x;`, reads input into variable `x`. (Similar to Javas `Scanner`, but C++ I/O is type-safe and reads whitespace-delimited tokens by default.)
- **Variables and Memory变量与内存** A variable in C++ has a **name (identifier, 标识符)**, a **type类型**, and stores a value in memory. All variables **must be declared before use先声明后使用**. Common primitive types: `int` 整型, `double` 双精度浮点, `char` 字符型, `bool` 布尔型 (布尔值用`true`/`false`). C++ types correspond to Javas primitive types, but note that boolean values in C++ can be implicitly converted to integers (true为1, false为0), whereas Java strictly separates `boolean` from numeric types.
- **Operators and Expressions运算符与表达式** C++ supports arithmetic operators (`+ - * / %`), assignment operators (`=` and compound assignments like `+=`), and **relational operators关系运算符** (`== != < > <= >=`) for comparisons. Also logical operators (`&& || !`) for boolean logic. These work similarly to Java. One difference: In C++ you can use an `int` or other numeric in a condition (非零即真, 0为假), but in Java the condition of an `if` or loop must strictly be a boolean expression.
- **`if` Statement条件语句** Allows decision-making. **`if`** executes a block if a condition is true. **`if...else`** chooses one block if condition true, otherwise the else-block (如果条件为假则执行else部分). In C++, as in Java, conditions use `==` for equality (注意避免将`=`误用在条件判断中). C++99 introduced a **bool** type, so modern C++ uses `true/false` similarly to Java, but older C style (如使用0和1表示真假) is still valid.
- **`return` Statement返回语句** Ends a function and returns a value. In `main`, `return 0;` typically indicates successful execution. If omitted in C++ `main`, it defaults to 0. (Javas `main` is `void`, so it doesnt return a value to the system.)
**After-class Exercises 课后练习:**
1. **填空题:** 每个C++程序的执行从函数 ______ 开始。【提示】C++程序从`main`函数开始执行。
2. **填空题:** 大多数C++语句以 ______ 结束。【提示】C++语句以分号(`;`)结束。
3. **判断题:** 转义序列`\n`通过cout输出时会将光标移动到下一行开头。对/错)【提示】`\n`表示换行,输出它会换行,**因此表述正确**。
4. **判断题:** 所有变量在使用之前都必须先声明。(对/错【提示】C++要求变量先声明再使用,**该说法正确**。
*Suggested Answers 答案:* 1) **main**; 2) **分号** (即每条语句末尾加`;`); 3) 对。`\n`是换行符,会使输出换到新行; 4) 对。在C++中必须先定义变量类型和名称,然后才能赋值或使用它。请注意区分赋值运算符`=`和相等比较运算符`==`,避免在条件判断中误用。
## Lecture 3: Classes, Objects and Strings 第3讲类、对象与字符串
**Key Concepts 主要知识点:**
- **Class** A blueprint for creating objects (对象模版). A class defines a new **data type数据类型** that groups data and functions. For example, `class GradeBook { ... };` defines a `GradeBook` class. A class contains **data members数据成员** (also called **attributes 属性** or **fields 字段**) and **member functions成员函数** (also called **methods 方法**). By default, class members are **private私有** in C++ (only accessible by the classs own functions). Public interface is declared after the `public:` label. *(Java类默认成员可见性不同Java中成员缺省是包可见而C++类缺省是private。)*
- **Object对象** An instance of a class. When you create an object, e.g., `GradeBook myGradeBook;`, it allocates memory for the data members and allows you to call member functions on it. Each object has its own copies of the classs non-static data members (每个对象都有自己的一份数据成员). In OOP, an objects data should usually be kept private, accessed only via the classs public member functions (**encapsulation 封装**原则).
- **Member Function成员函数** A function defined inside a class, describing behaviors or operations on class data. For example, `displayMessage()` might print a welcome message stored in a `GradeBook` object. Member functions can be defined inside the class definition or separately (using the scope resolution operator `ClassName::functionName`). By default, member functions are not **virtual虚拟** unless specified (see Lecture 11 for polymorphism details). *(Java的方法默认是虚拟可覆盖但C++需要明确使用`virtual`才能实现运行时多态。)*
- **Access Specifiers访问说明符** Keywords like `public`, `private`, and `protected` that control access to class members. **`public` 公有** members are accessible from outside the class (接口API), while **`private` 私有** members are hidden from outside (只能被该类的成员函数访问). C++ class definitions often list public functions first (interface) and keep data members private. *(Java有类似的public/private修饰符还有protected和默认访问级别; C++的protected在继承时用后续讲解。)*
- **CamelCase Naming驼峰命名** By convention, C++ class names start with a capital letter and use capital letters to distinguish words (e.g., `GradeBook`), whereas function names typically start with lowercase (e.g., `displayMessage`). This is a stylistic convention to improve code readability (在代码中区分类名和函数名). Java uses a similar convention (类名首字母大写,方法名首字母小写).
- **Constructors构造函数** A special class member function that has the same name as the class and is used to initialize new objects (初始化对象). A **default constructor默认构造函数** is one that can be called with no arguments (either because it has no parameters or all parameters have default values). Constructors have no return type (not even void). In C++, if you do not define a constructor, the compiler provides a default constructor. Constructors are often used to set initial values for data members when an object is created.
- **`string` Class字符串类** C++ provides `std::string` (in `<string>` header) to represent text strings. You can create strings like `string s = "hello";` and use `s.length()` or `s.size()` for length, `s[0]` for character access, etc. This is similar to Javas `String` class, but C++ `std::string` is mutable (可变的) and uses value semantics (copy on assignment) unless otherwise specified. Older C-style strings use char arrays terminated by `'\0'`, but `std::string` is safer and easier. *(Java的String是不可变对象; C++的std::string可以修改内容例如`s.append("!");`添加字符。)*
- **Getters and Setters访问器和修改器** Its common to provide public member functions to **get** and **set** private data members. For example, a `GradeBook` class might have `getCourseName()` and `setCourseName()` to access a private `courseName` attribute. This preserves encapsulation by controlling how outside code interacts with class data. *(Java亦如此通常用getX/setX方法访问私有字段。)*
- **Separating Interface and Implementation头文件与实现** C++ practice is to put class definitions in a header file (e.g., `GradeBook.h`) and function implementations in a `.cpp` file, then include the header where needed. This separation allows multiple source files to include the class definition without duplication. Java does not separate interface and implementation in the same way; Java class definitions (fields and method signatures and bodies) are all in one `.java` file, but C++ encourages dividing the declaration (.h) and implementation (.cpp).
**After-class Exercises 课后练习:**
1. **填空题:** 每个类定义都以关键字 ______ 开头,后面紧跟类名。【提示】定义类以`class`开头,例如`class ClassName`
2. **填空题:** 类定义通常存储在文件以 ______ 扩展名结尾的文件中,以便被多处引用。【提示】头文件通常以`.h``.hpp`结尾。
3. **填空题:** 当每个对象都有自己的某个属性副本时,这种属性变量也称为 ______ 。【提示】实例成员变量,即**数据成员**。
4. **填空题:** 关键字`public`是一种 ______ 。【提示】`public`是访问说明符access specifier
5. **判断题:** 按照惯例,函数名应以大写字母开头,每个单词首字母大写。(对/错)【提示】函数名一般**不**以大写开头,而是首字母小写,所以该说法是**错**的。
6. **判断题:** 函数定义中紧随函数名的空括号表示该函数不需要任何参数即可执行。(对/错)【提示】空参数列表表示无参数,该说法**正确**。
7. **判断题:**`private`声明的数据成员或成员函数对该类的其他成员函数也是不可见的。(对/错)【提示】私有成员对本类的函数是可访问的,对类外才不可见,所以表述**错误**。实际上private成员可以被本类的成员函数访问。
8. **判断题:** 在某成员函数内部定义的变量称为数据成员,可以被该类的所有成员函数使用。(对/错)【提示】在函数内部定义的变量是**局部变量**,只能在该函数内部使用,不是整个类的成员,所以**错误**。
9. **判断题:** 每个函数体都由左花括号`{`开始、右花括号`}`结束。(对/错)【提示】函数体需用`{}`包围,**正确**。
10. **编程题:** *Invoice*发票类设计创建一个名为Invoice的类以表示商店售出的某项商品的发票。这个类应包含以下私有数据成员: 商品编号(字符串), 商品描述(字符串), 购买数量int, 单价int。为每个数据成员提供成对的`set``get`函数。此外,提供一个构造函数用于初始化所有成员,并提供一个名为`getInvoiceAmount`的成员函数来计算发票总额即数量乘以单价并返回该值int。如果购买数量或单价为负则将其设为0再计算总额。**要求:** 翻译以上需求,并给出实现提示。
## Lecture 4: Control Statements 第4讲控制语句
**Key Concepts 主要知识点:**
- **Algorithm算法** A procedure or formula for solving a problem, consisting of a sequence of actions in a specific order (一系列有序执行的操作). Writing an algorithm in simple steps before coding helps in program design.
- **Pseudocode伪代码** An informal, English-like way to describe an algorithms steps. Pseudocode is not actual code; it omits syntactic details and focuses on logic. It helps to plan programs without worrying about language syntax. (书写伪代码有助于先理清思路再将其转换为真正的C++代码。)
- **Control Structures控制结构** Basic constructs that dictate the flow of program execution. All programs can be built using three fundamental structures: **sequence顺序执行**, **selection选择执行**, and **iteration循环执行**. C++ (like Java) has corresponding **control statements控制语句** for each:
- **Sequence 顺序结构:** The default execution order where statements run one after another in the order written (顺序执行每条语句).
- **Selection 选择结构:** Making decisions. C++ provides **`if` 单分支** and **`if...else` 双分支** statements, and the **`switch` 多分支** statement for multi-way branching. The `if` statement executes a block if a condition is true; `if...else` chooses between two blocks. The `switch` statement tests an integer (or enum/char) expression and executes the case matching that value (each `case`标签后跟要执行的语句块). *Javas `switch` is similar but can also use strings; C++17开始也允许`switch`字符型或枚举型传统C++中`switch`不支持字符串。*
- **Iteration 循环结构:** Repeating actions. C++ has **`while`** and **`for`** loops (可能执行零次或多次) and a **`do...while`** loop (至少执行一次). A **`while` loop当型循环** repeats as long as a condition remains true (先检查条件,再执行循环体). A **`for` loop计数循环** is typically used for a known number of iterations, with initialization, condition, and increment in one line. A **`do...while` loop后测试循环** executes the body first, then checks the condition to decide if it should repeat. In all these, a loop condition works like an `if` condition: in C++ nonzero means true, zero means false. *(Java的循环与C++基本一致,也有`while`, `for`, `do...while`但注意Java中必须使用布尔表达式作为循环条件C++中整数也可作为条件使用。)*
- **`if` and `if...else` (条件语句)** The `if` structure allows conditional execution. Syntax:
```cpp
if (condition) {
// true block
} else {
// false block
}
```
If the **condition条件** is true (非0或`true`), the first block executes; otherwise the `else` block executes (if present). Use braces `{}` to group multiple statements in a block. *良好习惯即使只有一条语句也使用花括号以避免歧义Good practice to always use braces for clarity.* You can nest ifs for multiple levels of decision (嵌套的if结构处理更复杂的条件).
- **`switch` Statement多路分支** Used for multi-way branching based on an integer or enum expression. Syntax:
```cpp
switch (expression) {
case constant1:
// statements
break;
case constant2:
// statements
break;
...
default:
// statements
}
```
The **`case` labels分支标签** must be constant expressions. The `switch` transfers control to the matching case. Without an explicit `break`, execution will “fall through” to the next case (贯穿后续case). Typically, each case ends with `break` to prevent fall-through (除非有意连续执行). The `default` label handles any value not matched by cases. *(Java的switch相似但在Java中使用字符串作为case是允许的而传统C++不直接支持字符串。无论C++还是Java都需要break避免贯穿。)*
- **Loops循环** Three types in C++:
- **`while` loop当型循环**: Checks condition first, then executes loop body if condition is true. Continues checking and executing until condition becomes false. Example: `while (x > 0) { x--; }`. If condition is initially false, the loop body may not execute at all.
- **`do...while` loop至少执行一次的循环**: Executes the loop body **at least once** and then checks the condition at the end. Syntax:
```cpp
do {
// body
} while(condition);
```
Useful when the loop body should run at least one time (例如菜单处理,需要先显示菜单再判断是否重复).
- **`for` loop计数循环**: Typically used when the number of iterations is known or to iterate over a range. Syntax:
```cpp
for ( initialization; condition; increment ) {
// body
}
```
Example: `for(int i=0; i<5; ++i) { ... }` will loop 5 times (i从0到4). The `for` loop is essentially a compact form of a while: initialization executes once at loop start, then each iteration checks condition and executes body, then performs increment step. C++11 adds a **range-based for loop基于范围的for循环**, e.g., `for(int val : array) { ... }`, to iterate over containers/arrays easily (类似Java增强for循环).
- **`break` and `continue`** Within loops (以及switch中), **`break`(跳出)** immediately exits the loop (终止当前循环), and **`continue`(继续下轮)** skips the remaining statements in the loop body and proceeds with the next iteration (提前进入下一次循环判断). Use these carefully to avoid confusing flow. *(Java中break/continue语义相同。)*
- **Logical Operators逻辑运算符** `&&` (AND), `||` (OR), and `!` (NOT) are used to form complex conditions (组合多个条件). They work similarly to Java, including short-circuit evaluation (短路求值): in `expr1 && expr2`, if `expr1` is false, `expr2` is not evaluated at all. Likewise for `||`: if the first operand is true, the second is skipped. Use parentheses to clarify logic when needed.
- **Compound Assignment复合赋值** Operators like `+=`, `-=`, `*=`, `/=`, `%=` for combining arithmetic with assignment. E.g., `x += 5;` adds 5 to x (相当于 `x = x + 5;`). These make code concise. C++ also has **increment/decrement operators自增/自减)**: `++x` or `x++` to add 1, `--x` or `x--` to subtract 1. Prefix (`++x`) vs postfix (`x++`) matters in expressions (前置返回新值, 后置返回旧值), but as standalone statements both increment x. (Java also has these operators with the same behavior.)
- **Data Type Portability数据类型可移植性** An awareness point: Fundamental types like `int` may have different sizes on different platforms (e.g., 32-bit vs 64-bit systems). C++ defines minimum ranges (e.g., `int` at least ±32,767) but not exact sizes in the language standard. Javas primitive types have fixed sizes (e.g., int is always 32-bit) making them more portable across platforms. C++11 introduced fixed-width types (如`int32_t`) in `<cstdint>` for precise control when needed.
- **Boolean context布尔上下文:** In C++, an `int` or pointer can be used in a boolean context (非零即真), whereas Java requires a true boolean value for conditions (在Java中使用非boolean作为条件会编译错误). For example, `while(n)` is valid in C++ (loops while n≠0), but in Java you must write `while(n != 0)`.
- **Switch limitationsswitch的限制:** C++ `switch` can use integral types (int/char/enum) but not strings or objects. Javas `switch` (since Java 7) allows `String` and wrapper types. Also, C++ does not automatically break at the end of a case (必须手工`break`防止贯穿), same as Java. Both languages support a `default` case.
- **Loop features:** Both anguages support `break` and `continue` inside loops. Java adds labeled breaks/continues; C++ doesnt have labeled loop control (no equivalent to Javas `label:` with break label).
- **for-each loop:** Modern C++ (`range-based for`) is akin to Javas enhanced for loop for arrays/collections. Syntax differs slightly but concept is the same (iterate through elements directly).
- **do...while:** Present in both languages with identical behavior (loop executes at least once).
- **No implicit type conversion to boolean in Java:** Java不会将数字自动转为布尔这在C++中需要注意如果将C++代码移植到Java要显式比较==0或!=0。
- **Precision of types:** As mentioned, Javas types have fixed size (e.g., `int` 32-bit), whereas C++s may vary; this can affect loop ranges or portability if you assume a certain size in C++.
**After-class Exercises 课后练习:**
1. **判断题:** 在`if`语句中,若条件不加括号也能正常编译运行。(对/错)【提示】条件必须放在圆括号内,漏写括号会导致语法错误,**错误**。正确格式如:`if (x > 0) {...}`。
2. **判断题:** 在`switch`的每个`case`分支后都应使用`break`来防止执行落入下一个分支。(对/错)【提示】一般应加`break`避免“贯穿”行为,**正确**。如需特意贯穿,可以省略,但必须十分小心。
3. **判断题:** 在`for`循环中使用`continue`语句会提前跳出整个循环。(对/错)【提示】`continue`只是跳过本次余下循环并进入下一次迭代,不会终止循环,**错误**。结束整个循环应使用`break`。
4. **编程题:** **判断回文数Palindrome** 定义一个函数`bool isPalindrome(string str)`,如果字符串正着读和反着读都相同则返回`true`,否则返回`false`。例如:"madamimadam"是回文。请将此函数补充完整。
**提示:** 所谓“回文”指序列从前往后和从后往前相同。解决思路:可以使用两个索引分别从字符串头部和尾部向中间移动,逐字符比较是否相等。一旦发现对应字符不相等,就可以断定不是回文。若所有字符成对匹配,则是回文。如:
```cpp
bool isPalindrome(string str) {
int i = 0, j = str.length() - 1;
while(i < j) {
if(str[i] != str[j])
return false;
i++;
j--;
}
return true;
}
```
此函数遍历字符串的一半长度即可完成判断时间复杂度为O(n)。在调用时可传入数字的字符串形式进行判断也可以先将int转换为string再调用。*(In Java, one could similarly check by comparing `str.charAt(i)` and `str.charAt(j)` in a loop.)*
## Lecture 5: Functions, Recursion and Overloading 第5讲函数、递归与重载
**Key Concepts 主要知识点:**
- **Functions函数** Named blocks of code that perform a specific task, improving modularity (模块化) and reuse. Functions in C++ can be **standalone (free) functions自由函数** or member functions of classes. A function **definition定义** consists of a return type, name, parameter list, and body. A **function call调用** executes the functions body. For example, `int add(int a, int b) { return a+b; }` defines a function `add` that returns an int sum, and you call it as `int result = add(3,4);`. Functions allow **divide-and-conquer programming** by breaking a program into smaller pieces. *(Java的方法类似但Java没有独立的全局函数所有方法必须属于类C++既有类成员函数也允许全局函数定义。)*
- **Function Prototype函数原型** A function declaration that specifies the functions interface (name, return type, parameters) without the body. For example, `int add(int, int);` is a prototype. Prototypes (often placed in headers) allow the compiler to know about a function before its definition appears, enabling calls from code that comes lexically before the functions definition. The compiler uses the prototype to verify calls (参数类型和数量是否匹配) and perform **type coercion类型转换** for arguments if needed. In C++, you **must** either declare or define a function before calling it (Java doesnt require forward declarations because the one-pass compiler or JIT knows all class methods by design).
- **Parameters and Arguments形参与实参** **Parameters形式参数** are variables declared in the function definition/prototype to receive data, and **arguments实参** are the actual values passed to the function when called. The number, order, and types of arguments must match the functions parameters (except where default parameters are used). C++ evaluates arguments left-to-right (evaluation order unspecified in older C++ standards, but guaranteed in C++17). By default, C+。+ uses **pass-by-value值传递**, meaning the function gets a copy of the arguments (函数操作形参不会影响调用者提供的实参变量). You can also use **pass-by-reference引用传递** or pointers to allow the function to modify caller variables (e.g., `void foo(int &x) { x = 5; }`). *(Java方法参数传递都是值传递但对象引用作为值传递可以间接修改对象的内容。Java没有C++引用这种语法,但对象参数可改变其内部状态。)*
- **Return Value返回值** The value a function gives back after completion, specified by the functions return type. Use the `return` statement to return a value and exit the function. If a function is declared with a non-void type, it should return a value of that type. If the function is `void`, it does not return a value (though it can use `return;` to exit early). In C++, failing to return a value from a non-void function results in undefined behavior (Java would not compile such a method).
- **Void Functionsvoid函数** Declared with `void` return type, they do not return any value. They typically perform actions like printing or modifying global state. For example, `void printMessage() { cout<<"Hi"; }`. You call it as `printMessage();` and theres no result to use. (Javas `void` methods are analogous.)
- **Local and Global Variables局部和全局变量** **Local variables局部变量** are those defined inside a function (including parameters), which exist only during function execution and are not known outside. Each call creates new instances of local variables (stored on the **stack 栈**). **Global variables全局变量** are defined outside any function, accessible from any code after their declaration (unless restricted by `static` or namespaces). Global variables in C++ have program duration (allocated in static storage). Its good practice to minimize globals for modularity.
- **Storage Class and Lifetime存储类与生命周期** C++ variables have storage durations: **automatic自动存储期** for locals (allocated on function entry, freed on exit), **static静态存储期** for globals and `static` local variables (allocated when program starts or when first encountered for local statics, freed at program end), and **dynamic动态存储期** for memory allocated via `new` (lives until `delete`). For example, a `static int count;` inside a function retains its value between calls (第一次调用时初始化一次,以后调用保留之前的值). Java manages object lifetimes with garbage collection and has no direct equivalent to C++ manual memory allocation in terms of keywords (no `new`/`delete` pairing visible to programmer; Javas `new` automatically managed by GC).
- **Math Library Functions数学库函数** C++ `<cmath>` header provides common functions like `sqrt()`, `pow()`, `sin()`, etc. These are global (not class members) and can be called by including `<cmath>` and writing e.g. `double r = sqrt(4.0);`. (Java has similar math functions in `java.lang.Math` as static methods, e.g., `Math.sqrt(4.0)`).
- **Function Overloading函数重载** C++ allows multiple functions with the **same name** but different parameter lists (不同的参数签名) in the same scope. The compiler distinguishes them by their **signature函数签名** the combination of function name and parameter types (顺序及数量). For example, you can have `int max(int,int)` and `double max(double,double)`. When you call `max(3,5)`, the int version is invoked; `max(3.5, 4.2)` calls the double version. Overloading lets you use a common name for conceptually similar operations on different types. *(Java also supports method overloading in classes. In both languages, return type alone is not enough to overload; 参数列表必须不同。)* The compiler uses **name mangling名字改编** under the hood to encode parameter types in the symbol name, enabling type-safe linkage.
- **Default Arguments默认参数** C++ allows you to specify default values for parameters in function declarations. For instance, `void print(int count = 1)` means if `print()` is called without an argument, `count` will default to 1. Default arguments must be the rightmost parameters, and if you omit one argument in a call, you must omit all to its right. Java does not have default parameters; instead, you overload methods to achieve similar behavior. *(注意:默认参数值在函数声明处给出,在调用时若不传该参数则使用默认值。)*
- **Inline Functions内联函数** Declared with the keyword `inline` (or defined directly in class definition for member functions), these suggest to the compiler to expand the function body at the call site to avoid function call overhead. Useful for very short functions. Modern compilers optimize short functions automatically, so explicit `inline` is less critical. (Java inlining is handled by the JIT at runtime and not exposed in source.)
- **Recursion递归** A programming technique where a function calls itself (直接或间接调用自身). Recursive solutions have a **base case基例** that stops recursion and one or more **recursive cases递归情况** where the function calls itself with a smaller sub-problem. For example, the factorial function can be defined recursively: `factorial(n) = n * factorial(n-1)` with base case `factorial(0)=1`. Each recursive call has its own set of local variables (stack frame) on the **function call stack调用栈**. If recursion doesnt converge to a base case, it results in infinite recursion (类似无限循环) and eventually a stack overflow (栈内存溢出). Recursion can produce elegant solutions for problems like factorial, Fibonacci, tree traversal, etc., but iterative solutions (使用循环) may be more efficient in some cases. C++ and Java both support recursion similarly.
- **Recursive vs Iterative递归与迭代对比** Both recursion and looping achieve repetition. **Iteration迭代** explicitly uses loops, modifying loop variables until a condition fails. **Recursion** uses repeated function calls, letting the runtime handle looping via the call stack. Recursion can be more readable for divide-and-conquer algorithms (分治算法), but each function call has overhead. For example, calculating Fibonacci recursively leads to many duplicate subcalls, whereas an iterative approach or memoization is more efficient. Its important to choose the right approach based on clarity and performance. *(在Java中也是如此递归容易栈溢出且有函数调用开销但写法简洁; 有些算法(如遍历树结构)递归实现更直观。)*
**After-class Exercises 课后练习:**
1. **填空题:** 只在定义所在函数内可见的变量称为 ______ 变量。【提示】这类变量是局部变量local variable
2. **填空题:** 在被调用函数中使用 ______ 语句可以将表达式的值传回调用函数。【提示】使用`return`语句返回值。
3. **填空题:** 函数头中使用关键字 ______ 表明该函数不返回任何值。【提示】`void`关键字。
4. **填空题:** 可以定义多个同名但参数不同的函数供不同数据类型使用,这称为函数 ______ 。【提示】**函数重载** (function overloading)。
5. **填空题:** 使用限定符 ______ 声明的变量为只读变量(不能被修改)。【提示】用`const`限定符声明常量。
6. **判断题:** 一个类可以定义多个与类同名的函数来构造对象。(对/错)【提示】**对**。类可以有多个构造函数,参数不同即构成重载。
7. **判断题:** 如果函数参数需要多个值,那么函数调用时参数和形参在类型、顺序和数量上必须一一对应。(对/错)【提示】**对**。实参会按照位置依次匹配形参,类型必须兼容或可转换,否则编译错误。
8. **判断题:** 用关键字`inline`声明的函数编译后一定会内联展开,不会发生函数调用开销。(对/错)【提示】**错**。`inline`只是建议具体是否内联由编译器决定。另外即使没声明inline编译器有时也会优化内联。
9. **判断题:** 递归和迭代都会重复执行操作,但递归可能导致较高的函数调用开销和内存占用。(对/错)【提示】**对**。递归调用频繁压栈出栈,开销较大;迭代通常更节省资源。如果递归层次太深还可能导致栈溢出。
10. **找错改错:** 下列代码包含若干错误,请说明并更正。
```cpp
void g() {
cout << "Inside function g" << endl;
void h() {
cout << "Inside function h" << endl;
}
}
float cube(float); // function prototype
cube(float number) {
return number * number * number;
}
```
**提示:** 存在两个主要错误首先C++中不允许在函数`g`内部定义另一个独立的函数`h`(不能在函数内嵌套定义函数)。应将`h`的定义移到`g`外部。同理,每个函数的花括号必须匹配,`g`函数在定义`h`之前就应该闭合其作用域。其次,`cube(float number)`函数的定义缺少返回类型,应与前面的原型一致返回`float`。修改如下:
```cpp
void g() {
cout << "Inside function g" << endl;
}
void h() {
cout << "Inside function h" << endl;
}
float cube(float number) {
return number * number * number;
}
```
以上更正包括:将`h`定义为独立的`void h()`函数,并为`cube`函数添加返回类型`float`使其与声明匹配。此外,确保每个函数的定义都有匹配的花括号闭合。经过修改,代码可正常编译,函数调用关系也清晰明确。
## Lecture 6: Arrays and Vectors 第6讲数组与向量
**Key Concepts 主要知识点:**
- **Array数组** A collection of elements of the **same type相同类型** stored contiguously in memory. Think of an array as a series of numbered boxes, each holding a value of a particular type. You refer to an element by its **index索引/下标)**, an integer offset from the start of the array. In C++ (and many languages), array indexing starts at **0** (首元素索引为0). For example, if `int a[5];` is an array of 5 ints, valid indices are 0 through 4. The number inside `[]` is the arrays length (元素数量).
- **Declaring Arrays数组声明**: Use syntax `Type arrayName[arraySize];`. This allocates memory for `arraySize` elements of `Type`. The size must be a constant expression (编译时常量) in C++ for static arrays. Its recommended to use a constant or `#define` for array sizes to avoid “magic numbers” (不直接使用字面值) in the code.
- **Accessing Elements访问元素**: Use the subscript operator `[]`, e.g., `a[2]` refers to the third element of array `a`. Indices must be integers (or integer expressions). Be careful: C++ does **not perform bounds-checking不自动检查下标越界** on array accesses. Accessing an out-of-range index causes undefined behavior (可能读取无效内存或导致程序崩溃). In contrast, Java throws an exception if you index out of bounds. Always ensure index `0 <= index < arrayLength`.
- **Initializing Arrays数组初始化**: You can initialize an array when you declare it. For example: `int b[3] = {1, 2, 3};` or `int c[5] = {0};` (initializes all 5 elements to 0). If the initializer list has fewer elements than the array, remaining elements are initialized to 0 (implicitly). If the array size is omitted, the compiler deduces it from the initializer count. *(Java数组初始化类似但Java数组是对象在运行时动态分配; C++静态数组在栈或静态存储上分配。)*
- **Constant for Array Size常量数组长度**: Its good practice to use a `const` variable for array size, e.g., `const int SIZE = 10; int arr[SIZE];`. This makes the code more maintainable (eliminates “magic number”) and clearly communicates the array length. Note: In modern C++ you can also use `std::array` or `std::vector` which manage size dynamically or at compile time.
- **Array Index (Subscript)(数组下标)** The index is the position of an element. Also called **subscript下标**. The first element is index 0, last element index = size-1. Using an index outside this range leads to invalid memory access (C++不会自动抛异常,因此务必小心)。For example, if `int a[5];`, `a[5]` is an invalid access (有效索引为0~4)。
- **Memory Layout内存布局** Arrays are stored in contiguous memory. If `a` is an `int[5]`, and on a system `int` is 4 bytes, then `a[0]` is at some address `p`, `a[1]` is at `p+4`, `a[2]` at `p+8`, etc. Pointer arithmetic can be used with arrays (Lecture 7). C++ does not store the array length with the array (unlike Java which has `array.length` property). You must track the size separately.
- **Constant vs Variable Length Arrays**: Traditional C++ (pre-C++11) required array size to be a compile-time constant for stack allocation. Some compilers allow variable length arrays (VLAs) as an extension, but the portable way for dynamic size is to allocate on heap or use `std::vector`. *(Java数组长度是在运行时确定的通过`new`分配C++也可以用`new`动态分配数组,或使用标准容器。)*
- **Arrays Initialization Pitfalls初始化注意**: If you partially initialize (e.g., `int d[5] = {1,2};`), uninitialized elements are set to 0 in C++ for static storage or if initializer list is provided. However, if you omit an initializer entirely for a local array, the array contains **garbage values未定义垃圾值**. Always initialize or set values before use.
- **const Arrays常量数组**: Declaring an array as `const` (e.g., `const int arr[3] = {…};`) makes its elements read-only. Alternatively, using `constexpr` for compile-time constant arrays. (Java has final arrays references, but array elements can still change unless individually final; C++ const truly makes each element constant.)
- **Multidimensional Arrays多维数组** C++ allows arrays of arrays, e.g., `int matrix[3][4];` is a 3x4 matrix (3 rows, 4 columns). Access via `matrix[i][j]`. These are stored in row-major order (行优先存储). You must specify sizes for all but the first dimension when passing to functions. Javas multi-dimensional arrays are actually arrays of array objects (could be ragged), while C++ multi-dimensional arrays are true multi-dimension in contiguous memory (unless you use pointers to simulate jagged arrays).
- **Static vs Automatic Arrays**: A **static local array静态局部数组** (declared with `static` inside a function) persists for the programs lifetime and is zero-initialized by default. An **automatic array自动/局部数组)** (normal local array) is created each time the function is called and destroyed on exit; it is not automatically initialized (contents are indeterminate if not set). Use static when you need to preserve values between calls or for large arrays to avoid stack usage (but then not thread-safe).
- **Range-Based for (C++11)基于范围的for循环** You can loop through an array easily: `for(int x : arr) { ... }` will iterate over each element `x` in `arr`. This is similar to Javas enhanced for: `for(int x : arr)`. Its read-only by default (x is a copy). Use reference (`for(int &x : arr)`) if you want to modify array elements in the loop.
- **No Built-in Bounds Checking无边界检查** Unlike Java, C++ will not throw an error if you go out of bounds on an array; it will just access whatever memory is at that address. This can lead to bugs or security issues. For safer arrays, use `std::array` (which has `.at(index)` that throws an exception on out-of-range) or `std::vector` (with `at` method). In critical applications, consider using these or adding manual checks.
- **C-Strings vs std::string**: A C-style string is an array of `char` ending with `'\0'`. e.g., `char name[6] = "Alice";` (actually 6 elements including null terminator). Manipulating C-strings requires care (functions in `<cstring>` like `strcpy`, `strlen`). `std::string` (as covered in Lecture 3) is higher-level and easier to use. When interacting with C APIs, you might convert `std::string` to C-string via `c_str()` method.
- **Class Template `std::vector`(向量模板类)** A dynamic array provided by the C++ Standard Library (in header `<vector>`). **`std::vector<T>`** represents a resizable array of elements of type T. Key features:
- **Dynamic sizing动态大小**: It can grow or shrink at runtime. Start with `vector<int> v;` and use `v.push_back(value);` to append elements. The vector manages its own memory (automatically allocates more space as needed).
- **Access and Capacity访问与容量**: Use `v[index]` to access elements (like array, but no bounds check by operator[]), or `v.at(index)` which throws `std::out_of_range` exception if index is invalid. Use `v.size()` to get current number of elements. Unlike built-in arrays, `vector` knows its length.
- **Initialization**: You can initialize with a size: `vector<int> v(10);` creates a vector of size 10 (elements default-initialized, e.g., 0 for int). Or initialize with values: `vector<int> v = {1,2,3};`.
- **Comparison**: Vectors can be compared with `==` and `!=` (element-wise comparison). Two vectors are equal if they have same length and all corresponding elements equal.
- **Copy and Assignment拷贝与赋值**: You can assign one vector to another (`v2 = v1;`) and it copies all elements (深度复制,每个元素都会被拷贝). There is also a copy constructor (e.g., `vector<int> v2(v1);`) to initialize from another vector.
- **Memory Reallocation**: Vectors manage an internal capacity. They might allocate more capacity than size for efficiency. When size exceeds capacity, a reallocation happens (which can move the data). Thus pointers/iterators to vector elements may be invalidated when reallocation occurs. (Javas `ArrayList` is similar in this regard.)
- **Bounds Checking**: `vector::at` provides bounds checking. In contrast, `operator[]` does not check bounds (for performance). Javas `ArrayList` `get(index)` does check and throws exception if out of range.
- **Default initialization**: A `vector<int> v(5);` will value-initialize the 5 ints to 0, whereas a built-in array of 5 ints (if local) would be uninitialized unless explicitly set.
- **Iterators**: Vectors provide iterators (like pointers) to traverse elements. Example: `for(auto it = v.begin(); it != v.end(); ++it) { cout<< *it; }`. (Similar to Java iterators, but in C++ often we use range-for instead for simplicity.)
- **Advantages**: `std::vector` is safer and more flexible than raw arrays. Use it unless you have a specific reason to use C-style arrays.
**After-class Exercises 课后练习:**
1. **填空题:** 定义数组长度时应使用 ______ 来避免魔术数字magic number。【提示】应使用符号常量例如`const`常量或宏。
2. **填空题:** 用来引用数组特定元素的数字称为该元素的 ______ 。【提示】称为**下标**或索引subscript/index
3. **判断题:** 一个数组可以存储多种不同类型的值。(对/错)【提示】**错。**数组中的所有元素类型必须相同。例如,`int`数组只能存`int`,不能混存其它类型。
4. **判断题:** 数组的下标值通常应使用`float`类型,以便表示更大的范围。(对/错)【提示】**错。**数组下标应使用整数类型(如`int`),浮点数不可直接作为下标(编译时会转换或报错)。
5. **判断题:** 如果初始化列表中的初始值个数少于数组长度,未提供初始值的元素将被初始化为列表中的最后一个值。(对/错)【提示】**错。\**对于不足的部分C++会将其\**初始化为0**(数值类型)而不是重复最后一个值。
6. **判断题:** 如果初始化列表中的值多于数组容量,这将导致编译错误。(对/错)【提示】**对。**初始化时初始值数量不能超过数组声明的大小,否则程序无法通过编译。
7. **编程题:** 定义一个大小为99的浮点数组`w`,写一个程序找出并输出该数组中的最小值和最大值。要求:给出中文解题思路。
**提示:** 可以通过一次遍历数组来同时找出最小值和最大值。具体步骤:先假设数组首元素既是最小值又是最大值,然后从第二个元素开始遍历整个数组,与当前最小值、最大值比较并更新。如伪代码:
```
minVal = w[0], maxVal = w[0]
对于 i 从 1 到 98:
如果 w[i] < minVal则 minVal = w[i]
如果 w[i] > maxVal则 maxVal = w[i]
输出 minVal 和 maxVal
```
这样单次循环即可完成查找时间复杂度O(n))。需要注意数组必须已填入有效的数值才能进行比较(未初始化元素不能直接比较)。在实现中,先对`w`赋值可通过输入或随机生成等然后应用上述逻辑得到结果。请确保访问数组时索引不越界0到98。*(The approach is similar in Java: one would use a loop from 0 to length-1, updating min and max accordingly.)*
## Lecture 7: Pointers and Memory Management 第7讲指针与内存管理
**Key Concepts 主要知识点:**
- **Pointer指针** A variable that holds a **memory address内存地址** as its value. If a variable `x` resides at some address in memory, a pointer can “point to” `x` by storing that address. In C++, pointers are declared with an asterisk `*`. For example, `int *p;` declares `p` as a pointer to int (能够存放某个整型变量的地址). Pointers provide **indirection间接引用**: they allow access to the object they point to. *(Java没有显式的指针类型Java的引用在某种程度上类似指针但不能进行算术运算或转换为整数地址。)*
- **Address-of Operator `&`(取地址运算符)** A unary operator that yields the memory address of its operand. For example, if `int y = 5;` then `&y` gives the address where `y` is stored. You can assign that to a pointer: `int *yPtr = &y;` now `yPtr` contains ys address. Think of `&` as “give me the location of”.
- **Dereference Operator `\*`(解引用/间接运算符)** A unary operator used on a pointer to access the object it points to. For example, if `int *p = &y;` then `*p` refers to the same variable as `y`. So `*p = 10;` would set `y` to 10. `*` here is called the **indirection operator间接访问运算符**, and using `*p` is **dereferencing the pointer解引用指针**. *Important:* `*` has two roles in C++: declaration (to denote a pointer type) and dereferencing. The context differentiates them. *(Java does not allow direct pointer dereferencing; object references are automatically dereferenced with `.` operator to access fields/methods.)*
- **Pointer Declaration and Initialization指针声明与初始化** When declaring multiple pointers in one statement, note that the `*` applies to each variable individually: e.g., `int *p, q;` declares `p` as pointer to int and `q` as int (not a pointer). Its clearer to separate declarations. **Always initialize pointers初始化指针** when declaring if possible, either to a valid address or to `nullptr` (C++11) or `NULL` (older) or `0`. An uninitialized pointer contains an indeterminate address (野指针), dereferencing it causes undefined behavior. Setting a pointer to **null pointer空指针** indicates it points to nothing (a safe “nowhere” value). In C++ `NULL` is typically defined as 0; C++11 introduced `nullptr` as a type-safe keyword for null pointers.
- **Null Pointer空指针** A pointer that is not pointing to any object or function. In C++ you can assign `0` or `NULL` to a pointer to make it null. Dereferencing a null pointer (`*p` when `p` is null) is invalid and will likely crash the program (访问空指针会导致运行时错误). Always check `if(p != nullptr)` (or `if(p)` since null is falsey) before dereferencing if unsure. (Java references throw `NullPointerException` if used when null; in C++ its just undefined behavior with no automatic check).
- **Pointer Arithmetic指针算术** Pointers can be incremented or decremented (if they point to elements of an array). For example, if `p` is an `int*`, `p++` advances `p` to point to the next integer in memory (地址增加`sizeof(int)`字节). Likewise `p + n` moves the pointer forward by n elements. Pointer arithmetic is scaled by the pointed type size. So adding 1 to an `int*` moves 4 bytes (on typical 32-bit int system), adding 1 to a `double*` moves 8 bytes, etc. This is how C-style arrays and pointers are closely related (see next point). *(Java does not support pointer arithmetic at all. All array indexing in Java is done with the index and internal checks, not by moving pointers.)*
- **Arrays and Pointers Relationship数组与指针的关系** In C++, the name of an array can decay to a pointer to its first element. For example, if `int a[10];`, then `a` (in most expressions) is treated as `int*` pointing to `a[0]`. So you can do `int *p = a;` and then `*(p+3)` is equivalent to `a[3]`. Also, `a[i]` is defined as `*(a + i)`. There is a close interplay: pointer arithmetic + dereference can simulate array indexing. Note: Arrays allocated with `new` (like `int *p = new int[10];`) should be accessed with pointer notation `*(p+i)` or as if `p` were array name `p[i]`. One key difference: a pointer is a variable (you can reassign it), but an array name is not a modifiable lvalue (不能给数组名赋新地址值).
- **Pointer vs Reference指针与引用** C++ also has **references引用**, declared with `&` (e.g., `int &ref = x;`). A reference is an alias to an existing variable; once initialized to refer to a variable, it cannot be changed to refer to another. References are simpler (no deref operator needed: use `ref` directly as alias), but they cannot be null and must be initialized upon creation. Pointers, on the other hand, can be reassigned, can be null, and require explicit dereferencing. Both can be used for pass-by-reference to functions, but references are generally safer and preferred for that purpose. *(Javas object variables are more like pointers “under the hood,” but Java doesnt allow pointer arithmetic or direct memory access. Javas references are automatically dereferenced; you dont see an explicit `\*` as in C++.)*
- **Dynamic Memory Allocation动态内存分配** Using **`new`** to allocate memory on the heap. For example, `int *p = new int;` allocates an `int` and returns a pointer to it. For arrays: `int *arr = new int[50];` allocates an array of 50 ints on heap. Complement with **`delete`** to free a single object (`delete p;`) or **`delete[]`** for arrays (`delete[] arr;`) to avoid memory leaks (内存泄漏). If `delete` is not called, the allocated memory remains occupied until program ends. *Java doesnt have explicit `new`/`delete` pairing; it relies on garbage collector to reclaim unused objects.*
- **Memory Leaks and Dangling Pointers内存泄漏与悬空指针** A **memory leak内存泄漏** occurs if heap memory is allocated and never freed (在C++中忘记调用`delete`就丢失了指针). Over time, leaks exhaust memory. A **dangling pointer悬空指针** is a pointer that refers to memory that has been freed or is otherwise invalid. For example, if you `delete p;` and then still use `p` (without resetting it) its pointing to deallocated memory. Accessing it is undefined behavior. Best practice: after `delete p;` set `p = nullptr;` to avoid accidental use. Smart pointers from `<memory>` (like `std::unique_ptr`) help manage dynamic memory automatically (RAII idiom).
- **Pointer to Constant / Constant Pointer常量指针/指向常量)** C++ allows const qualifiers with pointers:
- `int * const p` is a constant pointer to int (指针自身是常量,不能改指向其他地址,但所指对象可变)。
- `const int * p` (or `int const * p`) is a pointer to a const int (指向常量的指针,不能通过*p修改对象但指针本身可变)。
- `const int * const p` is a const pointer to a const int (指针和所指对象都不可修改).
These add compile-time safety (e.g., if a function shouldnt modify what it points to, take `const T*`). Java doesnt have an equivalent; final references in Java mean you cant reassign the reference, but you can still modify the objects contents if its mutable.
- **Function Pointers函数指针** A pointer can also point to a functions address. Declaration syntax: `int (*fp)(int, int) = &functionName;`. This is advanced but allows passing functions as arguments (similar to delegates or lambdas in higher-level terms; C++11 has lambdas which are often easier). *(Java prior to 8 didnt have function pointers; Java 8 introduced lambda expressions and method references to achieve similar functionality.)*
- **Pointer Safety Enhancements (C++11)** Use `nullptr` instead of `NULL` for clarity and type safety. Use smart pointers (`std::unique_ptr`, `std::shared_ptr`) to automatically manage `delete`. These are part of modern C++ best practices to reduce manual memory errors.
**After-class Exercises 课后练习:**
1. **填空题:** 一元运算符`&`称为取地址运算符,用于获取其操作数的 ______ 。【提示】获取变量的**内存地址**。
2. **填空题:** 一元运算符`*`用于指针时称为间接运算符或解引用运算符,用于获取指针所指向的 ______ 。【提示】获取指针指向的**目标对象/值**。
3. **填空题:** 可以直接赋给指针变量的唯一整数值是 ______ 表示该指针不指向任何有效对象。【提示】整数0即空指针 `NULL`/`nullptr`)。
4. **判断题:** 在C++中,指针可以指向不同类型的变量,不需要类型匹配。(对/错)【提示】**错。**指针有类型,必须与所指对象类型一致或兼容(需要时可强制转换,但一般不安全)。例如,`int*`只能指向`int`或可转换为int的地址不能直接指向`double`
5. **判断题:** 指针与数组紧密相关,数组名在大多数表达式中会转换为指向其首元素的指针。(对/错)【提示】**对。**数组名可视为指向数组首元素的地址,如`a`可以作为`&a[0]`使用。因此`*(a+1)``a[1]`等价。
6. **判断题:** 使用`new`运算符分配的内存必须使用`delete`释放,否则会发生内存泄漏。(对/错)【提示】**对。**每次`new`都应有相应的`delete`,否则分配的堆内存无法回收,导致内存泄漏。可使用智能指针防止忘记释放。
7. **判断题:** C++引用reference类似指针但引用一旦绑定某对象后不可更改且不能为NULL。对/错)【提示】**对。**引用是对象的别名必须初始化一经绑定无法指向别的对象且不存在“空引用”。指针则可以在任何时候指向其他对象或设为NULL。
8. **判断题:** 将指针加1实际上使其指向下一个内存地址。对/错)【提示】**错**有细微差别。指针加1后指向下一个同类型元素的位置不一定是下一个字节地址而是跨过当前类型大小的字节数。例如`int*`加1跳过4字节到下一个int地址。
## Lecture 8: Classes Deeper Look (Part 1 & 2) 第8讲更深入的类机制 上、下)
**Key Concepts 主要知识点:**
- **Separate Header and Implementation头文件与实现分离** It is common to split a class into a **header file头文件** (`.h` or `.hpp`) and an **implementation file实现文件** (`.cpp`). The header contains the class definition (class declaration, with member function prototypes), and the implementation file contains the function definitions (函数定义) of those member functions. This separation aids maintainability: changes in implementation dont force recompilation of code that includes the header (as long as interface remains unchanged). To use a class in multiple source files, you include the header. For example, `#include "GradeBook.h"` in any file using `GradeBook` class. *(Java没有头文件—接口和实现都在`.java`文件内; 但Java可以通过interface和implementation classes来分离定义。C++头/源分离更贴近编译过程需求。)*
- **Default and Value Parameters in Constructors构造函数默认参数** Constructors (and any function) in C++ can have **default arguments默认参数**. This allows one constructor to handle multiple cases. For instance:
```cpp
class Player {
public:
Player(string name = "Anonymous", int level = 1) {
this->name = name;
this->level = level;
}
};
```
With this, you can construct `Player p1;` (uses defaults "Anonymous",1), or `Player p2("Alice");` (level defaults to 1), or `Player p3("Bob",5);`. At most one default constructor exists per class (构造函数默认为一个,因为参数默认可组合成无参调用)which is one that can be called with no arguments. If you provide default values for all parameters of a constructor, that constructor becomes the default constructor. *Java doesnt support default parameters; you must overload constructors instead.*
- **Destructor析构函数** A special member function with the same name as the class prefixed by `~` (如`~Player()`), called automatically when an object is destroyed (对象生命周期结束时调用). The destructors role is to free resources that the object may have acquired (like memory, file handles) before the object is removed from memory. Key properties:
- A class **has at most one destructor** (no overloading for destructors, no parameters, no return type). If you dont define one, the compiler generates a default destructor that simply calls destructors of data members (for class members) and does nothing special.
- Destructors are called automatically in the reverse order of construction (构造相反顺序) when objects go out of scope or are explicitly deleted. For example, in stack unwinding, local objects are destroyed in the opposite order of their creation.
- If an object is created with `new`, its destructor is called when you `delete` that object. If created as a local (stack) object, destructor called at end of scope. For global/static objects, destructors called when program terminates (in unspecified order across translation units).
- If `exit()` or `abort()` is called, destructors of some objects may not execute (especially `abort()` kills program without cleanup).
- **Important for memory management**: If your class allocates dynamic memory (via `new`), define a destructor to `delete` that memory to avoid leaks (or better use smart pointers to manage automatically). In classes that follow RAII (Resource Acquisition Is Initialization), the destructor releases the resource. Example: a file wrapper class closes the file in its destructor.
*(Java has no direct destructor concept; Java uses garbage collection. For cleanup (like closing files), Java relies on `finally` blocks or try-with-resources, or overriding `finalize()` (which is deprecated in Java 9+). Finalize is not deterministic and not recommended. In contrast, C++ destructors are deterministic and key to resource management.*
- **Constructor and Destructor Call Order构造和析构的顺序** For automatic objects (栈对象), constructors execute when entering their scope, destructors when leaving scope (like end of function or block). When multiple objects exist:
- If objects are defined in sequence, they are constructed in that sequence and destructed in reverse sequence (后创建的先析构).
- For class composition (对象成员): Member objects are constructed before the enclosing classs constructor body executes (in order of their declaration in the class) and destructed after the classs destructor body executes (in reverse order).
- For inheritance: Base class constructor runs before derived class constructor, and base destructor runs after derived destructor (base part is last constructed, first destroyed since derived “contains” base).
- **Global and static objects**: constructed before `main` begins (order across translation units not strictly defined), destructed after `main` exits (order is reverse of construction within each translation unit).
- If `exit()` is used, static objects might not destruct properly; if `abort()` used, none will.
- In summary: 构造函数调用按声明/继承顺序向内深入,析构函数调用按相反顺序向外展开。
- **Const Objects and const Member Functions常量对象与常量成员函数** If you declare an object as `const` (如`const Player p;`), it cannot be modified. In particular, you can only call that objects **const member functions常量成员函数**. A member function is made const by adding `const` after its parameter list, both in prototype and definition. For example,
```cpp
class Player {
public:
string getName() const { return name; }
void setName(string n) { name = n; }
private:
string name;
};
```
Here `getName()` is a const member function it promises not to modify the object (编译器会强制保证函数体内不修改成员变量). You can call `getName()` on a const Player, but cannot call `setName()` because that function isnt marked const. Const correctness helps catch unintended modifications and allows usage of objects in read-only context (like passing a const reference to a function to ensure it doesnt modify the argument). *Java does not have const methods or const objects. Instead, immutability in Java is a design choice (like making fields private and not providing setters, or using `final` for fields, but theres no language-enforced const for methods or objects). C++ const is a compile-time check to prevent modification through that interface.*
- **Composition组合** A class can have members that are objects of other classes (class A has a member of class B type). This is called a “has-a” relationship or composition (合成关系:一个类拥有另一个类的对象). For example, a `Car` class might have an `Engine` object as a member. Composition implies that the lifetime of the part (成员对象) is tied to the whole: when the Car is constructed, its Engine member is constructed; when Car is destroyed, Engine is destroyed. Its a way to reuse classes by building complex ones from simpler ones (Car由Engine, Wheel等部件组成). *(Java also has object references as fields to achieve composition, with similar semantics aside from memory allocation differences. In Java, an object field is a reference that could be null or refer to a shared object; in C++ if you have an object member (not pointer), its embedded and cannot be null it always exists as part of the containing object.)*
- **Friend Functions and Friend Classes友元函数与友元类** The `friend` keyword allows a non-member function or another class to access the private/protected members of a class. This is an exception to the usual encapsulation rules. For example:
```cpp
class MyClass {
friend void secretFunction(MyClass& obj);
friend class MyFriend;
private:
int secretData;
};
```
Here `secretFunction` and all members of `MyFriend` class can access `MyClass::secretData` directly. Friendship is granted, not taken: it must be declared within the class that is giving access. Its neither symmetric nor transitive: if A is friend of B, B is not automatically friend of A; if A is friend of B and B is friend of C, A is not friend of C. **Use cases:** sometimes needed for operator overloading (to allow an external function to access privates) or if two classes need intimate access to each others internals. But overuse of `friend` can break encapsulation and make maintenance harder, so use sparingly. *(Java has no friend concept. Java achieves similar trust through package-private access (classes in the same package can access each others package-private members) or simply making members public. But there's no direct way to allow one specific external function/class access without making things globally accessible, short of nested classes. C++ friend is a targeted relaxation of access control.)*
- **`this` Pointerthis指针** Inside a non-static member function, `this` is a pointer to the object on which the function was invoked. It has type `ClassName* const` (a const pointer to the object). You can use `this` to refer to the objects members (especially if names are shadowed) or to return the object itself (like in operator overloading chaining). In a const member function, `this` is of type `const ClassName*`. Java similarly has a `this` reference inside instance methods, though its used less explicitly (commonly only for disambiguating field names or passing the current object as parameter). In C++ you often see patterns like `return *this;` in methods to allow chaining.
- **Static Class Members静态类成员** C++ classes can have **static data members静态数据成员** and **static member functions静态成员函数**. A static data member is essentially a global variable that is scoped to the class (所有对象共享的类级变量). It exists independently of any object instances (即使没有创建对象,静态成员也存在并可访问). You define it *outside* the class as well (one definition in a .cpp): e.g., `int MyClass::count = 0;` to allocate it. Use cases: class-wide information, like a counter of how many objects have been created (each constructor increments, destructor decrements). Static member functions are functions not tied to a specific object (no `this` pointer inside). They can only access static members (because theres no object context). Call static members with class name: `MyClass::count` or `MyClass::staticFunc()`. *(Javas `static` fields and methods are analogous. The main difference: C++ static data members need to be defined in one .cpp file, whereas Java static fields are defined in the class itself at declaration. Also, C++ has no direct equivalent of Javas static initializer blocks, but you can assign initial values in the definition or use static constructors in modern C++17 (inline static initializations).)*
- If you want to call a static function or use a static data without any objects, you can do so. E.g., a class `MathUtils` could have `static double PI; static double square(double x);` and you use `MathUtils::PI` or `MathUtils::square(5.0)` directly (like Javas `Math.PI` and `Math.sqrt()`).
- Static data members are initialized to 0 (for fundamental types) by default if not explicitly initialized. They live in static storage (like global variables).
- A common pattern is **singleton**: a class with a private static instance of itself and a static method to get that instance.
- Remember to define static data in one translation unit or mark it `inline` (C++17) to avoid multiple definitions error.
- **Member Initializer List成员初始值列表** A syntax used in constructor definitions to initialize data members (especially important for const and reference members which **must** be initialized, not assigned). For example:
```cpp
class Example {
const int size;
int * data;
public:
Example(int s): size(s), data(new int[s]) { /*...*/ }
};
```
The part `: size(s), data(new int[s])` is the initializer list. It initializes `size` and `data` **before** the constructor body runs. Benefits:
- Efficiency: avoid default-constructing then assigning. For complex members, initialization can be faster than default construct + assignment (especially for objects of classes as members).
- Necessity: const and reference members cannot be assigned in constructor body; they must be initialized in the initializer list. Static data members cannot be initialized in the initializer list (theyre handled separately at definition).
- Order: Members are initialized in the order of their declaration in the class, not the order in the initializer list. Its wise to list them in same order to avoid confusion.
*(Java has no equivalent because instance fields can be assigned in body or an init block, but effectively Java does initialization before constructor body too, except you dont control the order beyond writing them in code order. Java final fields must be assigned by constructor completion but you usually just do it in constructor body or inline initializers, no special syntax needed.)*
**After-class Exercises 课后练习:**
1. **填空题:** 若要允许一个非成员函数访问类的私有成员,可以在类定义中将该函数声明为 ______ 函数。【提示】声明为该类的**友元friend**函数。
2. **填空题:** 对象的非静态成员函数可以通过一个隐含的“自我指针”访问所属对象,该指针称为 ______ 指针。【提示】称为`this`指针。
*(Lecture 8 slides did not explicitly list many exercise questions beyond friend and this pointer fill-in, so we focus on those.)*
**Suggested Answers 答案:** 1) **友元**函数; 2) **this**指针。请注意,`friend`关键字可以使指定的函数或类突破封装直接访问私有成员,但应谨慎使用。`this`指针在C++中是隐含参数,用于指向调用该成员函数的对象地址,在需要时可显式使用,如返回`*this`实现链式调用。
## Lecture 9: Operator Overloading 第9讲运算符重载
**Key Concepts 主要知识点:**
- **Operator Overloading运算符重载** C++ allows giving operators like `+`, `-`, `==`, `<<`, etc., custom meanings for user-defined types (为用户自定义类型定义运算符功能). This enhances expressiveness e.g., you can use `a + b` for two complex numbers or concatenate two strings with `+` if you define it. In C++, most operators can be overloaded except a few (notably `.` member access, `.*` pointer-to-member, `::` scope resolution, `?:` ternary, and `sizeof` cannot be overloaded). To overload an operator, you define a function with special name `operatorX` where X is the operator symbol. For example:
```cpp
class Complex {
public:
Complex operator+(const Complex& rhs) const {
return Complex(real + rhs.real, imag + rhs.imag);
}
};
```
This overloads `+` for Complex addition. Then `c1 + c2` calls this function (as a member function on `c1` with argument `c2`). Some operators are best overloaded as member functions (like assignment `operator=` must be member) and some as friend or free functions (like `operator<<` for streams, since left operand isnt a class object but an `ostream`).
- **Syntax**: If a binary operator is overloaded as a member, it takes one parameter (the right-hand side). If as a free function, it takes two parameters (left and right). For symmetric operations, free function can be friend for access.
- **Rules**: You cannot change operator precedence or associativity, and you cannot create new operators only overload existing ones. The overloaded operators arity (unary/binary) and meaning should be intuitive.
- **Example**: Overloading `<<` for output:
```cpp
std::ostream& operator<<(std::ostream& os, const Complex& c) {
return os << c.real << "+" << c.imag << "i";
}
```
This allows `cout << complexObj;` to print a Complex. Usually `operator<<` is a non-member (cannot be member of std::ostream or Complex), hence made a friend of Complex to access privates.
- **Operator=**: If you define custom copy semantics, overload assignment operator. If not, C++ provides a default member-wise copy assignment. Similarly, you can overload `operator==` to compare objects meaningfully (default does bitwise compare? Actually default `==` not generated, must overload for user types).
- **Conversion Operators类型转换运算符** You can define `operator type()` in a class to convert an object to another type implicitly. E.g., `operator int() const { return value; }` in a class would allow an object to be used where int is expected. Use carefully implicit conversions can introduce ambiguities or unexpected results. (In Java, you cant overload casting or define implicit conversions; you must use explicit methods).
- **Explicit Keyword** In C++11 and above, you can mark single-parameter constructors as `explicit` to avoid them being used as implicit conversions. Similarly, conversion operators can be marked explicit (C++20) to require explicit cast. This prevents unintended conversions. (Java doesnt have an equivalent since no user-defined implicit conversions exist.)
- **Overloading vs Overriding** Operator overloading is about same operator symbol working on different types (ad-hoc polymorphism). Its resolved at compile time by checking operand types. This is different from overriding virtual functions (runtime polymorphism, Lecture 11). (Java doesnt have operator overloading at all, so less confusion there; C++ needs careful distinction between overload vs override hence `override` keyword introduced for clarity in virtual functions override).
**After-class Exercises 课后练习:**
1. **填空题:** 要重载一元或二元运算符,需要定义一个名为 ______ 的函数。【提示】函数名形式为`operator+`、`operator==`等,例如重载`+`则函数名为`operator+`。
2. **判断题:** 运算符重载可以改变运算符的优先级从而影响表达式求值顺序。(对/错)【提示】**错。**重载运算符不会改变其既定的优先级和结合性,表达式求值规则保持不变。
3. **判断题:** Java允许用户为自定义类重载运算符。对/错)【提示】**错。**Java不支持运算符重载除了`+`用于字符串连接是语言内置特例外,其他运算符不可重定义。
*Answers 答案:* 1) 形如`operator+`的函数名(以`operator`加运算符符号命名); 2) 错3) 错。请记住C++运算符重载应遵循直观原则,例如`operator+`应实现类似“加法”的语义。不能重载的新运算符包括`.`、`::`、`?:`等。而在Java中运算符重载不可用只能通过定义方法实现类似功能例如用`add()`方法代替重载`+`号)。
## Lecture 10: Inheritance (Extending Classes) 第10讲继承 扩展类)
**Key Concepts 主要知识点:**
- **Inheritance继承** A mechanism for creating a new class (子类/派生类) from an existing class (基类/父类), absorbing its attributes and behaviors and optionally adding new features or overriding existing ones. In C++, class inheritance is specified with a **colon and access specifier**. Example: `class Student : public Person { ... };` means Student **inherits publicly from** Person (Student *is-a* Person). Key points:
- The derived class automatically has the data members and member functions of the base class (though private members of base are not accessible directly in derived, they are present but hidden). Public and protected base members become part of the derived class interface (public stays public, protected stays protected if using public inheritance).
- **Access specifier (public/protected/private) in inheritance**: This determines how the bases public/protected members are treated in derived.
- **Public Inheritance 公有继承**: The most common form. Base classs public members remain public in derived, protected remain protected. This models an “is-a” relationship: a Student is a Person, so it should be usable wherever a Person is expected (Liskov Substitution Principle).
- **Protected Inheritance 受保护继承**: Base public and protected become protected in derived. Not common; essentially, you dont want outside code to treat the derived as the base type.
- **Private Inheritance 私有继承**: Base public and protected become private in derived. Its more of a composition (“implemented in terms of”) than an is-a; not polymorphic. Rarely used except in certain design patterns or when you want to hide base interface.
*(Java only has a concept similar to public inheritance. All Java classes extend a base (explicit or `Object` implicitly), and all public/protected remain accessible in subclass. Java doesnt allow changing the access level of inherited members except you cannot reduce visibility of an overridden method.)*
- **Single vs Multiple Inheritance**: C++ supports multiple inheritance (一个子类可同时继承多个基类). Syntax: `class C : public A, public B { ... };`. This can lead to complexities like **diamond problem** if both A and B inherit from a common base (C++ resolves with virtual inheritance if needed). Java forbids multiple class inheritance; it allows multiple interfaces instead (interfaces are like pure abstract base classes).
- **Inheritance Hierarchies继承层次**: Classes can be derived multiple levels (子类的子类, etc.). At the root, often an abstract base class (see polymorphism in Lecture 11).
- Use inheritance when there is a clear generalization-specialization relationship (一般和特殊的关系). For example, `Person` as base, `Student` and `Teacher` as derived, sharing common attributes of Person but adding their own.
- **Protected Members保护成员** In C++, `protected` access means the member is accessible within the class and its derived classes (and also within the same module as friend or within same class scope). Protected is a way to allow subclasses to use base internals but keep them hidden from outside world. In Java, `protected` means accessible to subclasses *and* also to classes in the same package. C++ has no package concept, so protected is strictly subclass access (plus friend). Protected is useful when you want an inheritor to have some degree of access for convenience, but you dont want the general user (via a base class reference) to access those members.
- **Base and Derived Constructors基类与派生类构造** When you instantiate a derived class object, the **base class constructor runs first** to initialize the base part of the object, then the derived classs constructor runs. The derived constructor can call a specific base class constructor using an initializer list:
```cpp
class Student : public Person {
public:
Student(string name, int gradYear) : Person(name), graduationYear(gradYear) { }
...
};
```
If a base constructor requires arguments, you *must* call it explicitly in the initializer list. If you dont call any, C++ tries to call the bases default constructor implicitly. Similarly, **destructors** execute in reverse: first the deriveds destructor, then the bases destructor. This ensures proper construction/destruction chain. *(Java automatically calls the base class constructor (no syntax for choosing base constructor except via `super()` call as first line in subclass constructor). If you dont call `super(...)` explicitly, Java inserts a call to the no-arg super constructor. C++ similarly calls default base ctor if not specified.)*
- **Overriding and Hiding重写与隐藏** If a derived class defines a method with the same signature as a base class **virtual** method, it **overrides重写** that method (when called through a base pointer/reference, the derived version is used at runtime see Lecture 11 on polymorphism). If the base method is not virtual (just a normal function), then defining a same name in derived results in **hiding** (also called shadowing) which is not polymorphic; it simply means if you call that function on a derived object (statically typed as derived), you get the derived version, but if you call it on base or through a base pointer, you get base version because static binding. To override properly, the base function should be virtual.
- C++11 introduced the `override` keyword to explicitly mark overriding functions; the compiler will error if it doesnt actually override a base virtual. Use this to avoid mistakes (accidental signature mismatch). Java by default treats all non-final instance methods as virtual and overrides them if signatures match in subclass. Javas `@Override` annotation is like C++ `override` to catch errors.
- Also note: In C++, if you overload a function name in derived with a different signature, it *hides* all base class functions of the same name (even those with different signatures) from the scope. You can bring them in with `using Base::functionName;` if needed. Java doesnt have this exact issue because name resolution is always at compile-time by full signature, and methods with different sig are simply overloads existing in class. C++ name hiding is a quirk due to separate compilation and might require `using` to fix.
- **Multiple Inheritance and Virtual Base Classes多重继承与虚基类** If a class inherits from two classes that have a common base, the default is you get two copies of that base in the derived object (ambiguity which one to use). C++ allows **virtual inheritance** to solve the diamond problem, so the common base is shared (one subobject). Syntax: `class MyClass : virtual public BaseClass { ... };`. Virtual inheritance ensures only one base subobject even if base appears multiple times in hierarchy. This is advanced and only needed in certain MI scenarios. Javas way to avoid diamond is by not allowing multiple inheritance of classes at all (interfaces dont have state so diamond doesnt cause state duplication).
- **Polymorphism preview** (Though more in Lecture 11) Under inheritance, a derived object can be treated as a base object. You can assign a `Derived*` to a `Base*` (implicit upcast), or call a function expecting a Base reference with a Derived object. This is core to substitutability. If the function is virtual, the derived override will execute (if polymorphism is set up). If not virtual, base version executes (static binding). Non-polymorphic inheritance is essentially reuse of code without runtime flexibility.
**After-class Exercises 课后练习:**
1. **判断题:** 在公有继承下,基类的`public`成员在派生类中变为`private`。(对/错)【提示】**错。**公有继承不会降低可见性基类public成员在派生类中仍为publicprotected成员在派生类中仍为protected。只有`private`继承才会将基类的public和protected成员变为private。
2. **判断题:** C++允许一个类同时继承自多个基类。(对/错)【提示】**对。**C++支持多重继承一个派生类可有多个直接基类。但要注意可能出现“菱形继承”问题需要虚继承解决。Java不支持类的多继承。
3. **判断题:** 可以使用基类类型的指针或引用指向派生类对象。(对/错)【提示】**对。\**派生类对象\**是**一种基类对象,因此基类指针/引用可指向派生对象向上转型这实现了多态的基础。通过基类指针调用虚函数会执行派生类覆写的版本见Lecture 11
*Answers 答案:* 1) 错2) 对3) 对。请注意,在使用基类指针指向派生对象时,若调用非虚函数,则只会执行基类实现(静态绑定);只有虚函数才会多态地调用派生实现。良好的面向对象设计在继承层次中运用`public`继承表示”is-a”关系并尽量避免使用`protected`或`private`继承。此外尽管C++允许多继承但设计时需谨慎Java通过接口解决多继承需求这在C++中也可以用组合composition或虚继承达到类似目的。
## Lecture 11: Polymorphism and Virtual Functions 第11讲多态与虚函数
**Key Concepts 主要知识点:**
- **Polymorphism多态** Literally "many forms". In OOP, it refers to the ability to treat objects of different derived classes through a common base class interface, and have the correct overridden functions called according to the actual object type at runtime. Polymorphism enables you to **“program in the general rather than the specific”面向抽象编程而非面向具体实现**. The primary mechanism for polymorphism in C++ is **virtual functions虚函数**.
- Polymorphism lets you write code that works on base class pointers/references but actually processes derived class objects. For example, you might have a `Shape` base class with a virtual `draw()` method, and derived classes `Circle`, `Square` override `draw()`. If you store various shapes in an array of `Shape*` and call `draw()` on each, the appropriate derived class implementation executes (circle draws a circle, square draws a square).
- This relies on late binding (动态绑定): the decision of which function body to execute is made at runtime based on the actual object type, not at compile time (静态类型是基类,但对象实际类型是子类). Without virtual, C++ would do early binding (静态绑定) and call the base version always when using base pointer.
- Polymorphism usually goes hand in hand with **inheritance继承** and **virtual functions**.
- **Virtual Functions虚函数** Declared with keyword `virtual` in the base class, these functions are intended to be overridden in derived classes. A virtual function call is resolved dynamically at runtime via the **vtable虚函数表** mechanism. For example:
```cpp
class Base {
public: virtual void foo() { cout<<"Base"; }
};
class Derived : public Base {
public: void foo() override { cout<<"Derived"; }
};
```
Now, `Base* p = new Derived(); p->foo();` will print "Derived" because `foo` is virtual. If `foo` were not virtual, it would print "Base" (static binding).
- To override a virtual function in C++, the signature must match exactly (aside from `override` or covariant return). Marking the override with `override` (optional but recommended C++11) helps catch errors.
- **Pure Virtual Functions纯虚函数**: `virtual void foo() = 0;` in a class makes it abstract no implementation in base, derived classes must override it to be concrete. A class with any pure virtual is an **abstract class抽象类**, cannot be instantiated. This is similar to Javas abstract methods and abstract classes. Pure virtual functions allow defining an interface that derived classes must implement.
- Virtual functions can be overridden to provide specialized behavior in subclasses. If a subclass does not override a virtual, it inherits bases implementation. You can call base class version from derived if needed (explicitly `Base::foo();`).
- If a derived class fails to override a pure virtual, that derived remains abstract. All concrete (非抽象) derived classes must override all base class pure virtuals.
- **Virtual Destructor**: If a class is meant to be a base class (especially if delete via base pointer is possible), declare a virtual destructor. This ensures that deleting a derived object through a base pointer calls the deriveds destructor fully. In polymorphic base classes, the destructor should be virtual to avoid resource leaks. (Java has GC, so no concept of destructors; all objects properly finalize when collected. But if Java had manual deletion, their Object classs finalize is akin but not the same. C++ requires explicit management).
- **Dynamic Binding and Vtable动态绑定与虚函数表** At runtime, polymorphic objects carry a pointer to a vtable (a table of function pointers for virtual functions). When you call a virtual function, it uses the vtable of the actual objects class to jump to the right function. This indirection is why calls through base pointers go to derived overrides. Implementation detail: typically the first element of an object of a class with virtual functions is a vptr (虚指针) pointing to the table. (Javas method dispatch is similar in concept; all non-static, non-final methods in Java use a vtable-like mechanism for dynamic dispatch). The cost is one pointer dereference; negligible in most cases.
- **Polymorphic Interface and Extensibility** Polymorphism allows writing code that doesnt need to know exact subclasses in advance. For example, a function `printShapeArea(Shape& s)` can call `s.area()` and get correct result for Circle, Square, etc., without separate code for each. Adding new Shape types (Triangle, etc.) doesnt require changing `printShapeArea` its **extensible易扩展**. This is the Open-Closed Principle: modules open for extension (via new subclasses) but closed for modification. Polymorphism in C++ and Java achieves that.
- **Upcasting and Downcasting向上转型与向下转型** **Upcasting** is converting a derived object reference/pointer to a base type (安全且隐式进行). This is how we store derived in base pointer for polymorphism. **Downcasting** is converting base reference/pointer to a derived type. In C++, use `dynamic_cast<Derived*>(basePtr)` for a safe downcast (it returns nullptr if object isnt actually a `Derived`). This requires the base class to have at least one virtual function (so it has RTTI info). In Java, downcast uses `(Derived) baseRef`, which throws `ClassCastException` if the object isnt that type. The logic is similar: check actual type at runtime. If downcasting, ensure the object is indeed that subclass (via `dynamic_cast` or other means). Minimizing downcasts is often a design goal (rather use polymorphic virtual calls).
- **`typeid` and RTTI**: C++ provides `typeid` to get type info at runtime (for polymorphic types yields actual type). Java has `instanceof` or `getClass()`.
- If you find you need to downcast often, consider if virtual functions could handle the variation instead (polymorphism intended to reduce explicit type checking).
- **Abstract Base Classes抽象基类** A class with one or more pure virtual functions. It serves as an interface (perhaps partial implementation) that cannot be instantiated. Only concrete subclasses (classes implementing all pure virtuals) can be instantiated. Abstract classes in C++ correspond to abstract classes in Java (with abstract methods). They allow defining interfaces. For example, an abstract `Shape` with pure virtual `draw()` and `area()`, implemented by concrete `Circle`, `Rectangle`, etc. Attempting to create a `Shape` object would be a compile error (just like `new Shape()` illegal in Java if Shape is abstract).
- **Virtual Inheritance of Destructors** Emphasizing: if a class is meant to be base class (polymorphic), declare virtual destructor. If not, deleting derived via base pointer is undefined (the base destructor will run but not the deriveds portion). Polymorphic base classes typically have at least one virtual, so destructor should be virtual as well. (Java doesnt have this issue because all objects are tracked by GC; you dont manually delete and all parts get collected.)
**After-class Exercises 课后练习:**
1. **判断题:** 若基类的成员函数被声明为虚函数,则通过基类指针调用派生类对象的该函数时,会执行派生类版本。(对/错)【提示】**对。**虚函数调用会在运行时绑定到对象实际类型的实现。如果没有将其声明为virtual则不会发生多态。
2. **判断题:** 含有纯虚函数的类是抽象类,不能直接创建对象。(对/错)【提示】**对。**抽象类必须被继承并实现纯虚函数才能实例化对象。
3. **判断题:** 通过基类指针删除派生类对象时,应确保基类析构函数为虚函数,否则可能导致资源未正确释放。(对/错)【提示】**对。**基类析构应为virtual以便delete时调用派生类析构函数。否则行为未定义通常会导致只执行基类析构派生部分没释放造成内存泄漏或错误。
4. **填空题:** 要求所有派生类必须覆写某函数,可将该函数在基类中声明为 ______ 。【提示】将函数定义为纯虚函数pure virtual语法是在函数声明末尾加`=0`。
5. **填空题:** C++中,将`Base*`指针安全地转换为指向其派生类型对象的指针,应该使用的运算符是 ______ 。【提示】使用运行时类型识别的`dynamic_cast`。例如`dynamic_cast<Derived*>(basePtr)`。
*参考答案:* 1) 对; 2) 对; 3) 对; 4) **纯虚函数**; 5) **dynamic_cast**。以上强调:**多态**让我们可以通过基类接口操作不同派生类对象并自动调用恰当的实现。在设计类层次时基类应尽可能将接口函数声明为virtual并在需要强制子类实现时使用纯虚函数将类抽象化。另一方面如果类不打算作为基类使用则无需将析构函数声明为虚的这样略微减少虚表开销。Java程序员转到C++需特别注意虚函数的声明和`override`关键字的使用以避免逻辑错误。另外在需要判断对象实际类型时C++的`dynamic_cast`相当于Java的强制类型转换加`instanceof`检查它返回nullptr表示类型不匹配而Java则抛出异常。通过合理使用多态可极大提高代码的扩展性和可维护性。

View File

@@ -0,0 +1,32 @@
## BOM broswer
学习的是window 的属性以及window的API
```html
<button onclick="fun1()">弹窗</button>
<button onclick="fun2()">信息框</button>
<button onclick="fun3()">确认</button>
<script>
function fun1(){
window.alert("13eer");
}
function fun2(){
var s= window.prompt("输入姓名");
console.log(s);
}
function fun3(){
var c= window.confirm("要不要");
console.log(c);
}
```
## DOM document
![1732544555744](F:\Wechat\WeChat Files\wxid_13iogzk6c5q612\FileStorage\Temp\1732544555744.jpg)
也有节点
元素节点就是element 属性节点就是attribute 文本节点就是text

View File

@@ -0,0 +1,684 @@
# 实验一
> ## 如何建表 create Table
```sql
CREATE TABLE hhh(
id int auto_increment primary key,
name varchar(30) not null,
age int ,
birthday date,
is_actiove boolean default true
);
create table (
,
,
);
```
> ## 如何新增字段 Add column
```sql
Alter table role add age int not null
ALTER TABLE <> ADD <><>[];
```
> ## 如何增加数据
```sql
INSERT INTO products (maker, model, `type`) VALUES('A', '1001', 'pc'),
INSERT INTO (2.....)values `1`,`2`,`3`
```
> ## **DDL DML**
DDLData Definition Language语句 `数据定义语言`,主要是进行定义/改变表的结构、数据类型、表之间的链接等操作。常用的语句关键字有 CREATE、DROP、ALTER 等。
```sql
CREATE TABLE (
1 ,
2 ,
3 ,
...
)
ALTER TABLE ;
egALTER TABLE ADD ;
ALTER TABLE CHANGE ;
ALTER TABLE DROP ;
DROP TABLE ;
DROP DATABASE ;
```
DMLData Manipulation Language语句: `数据操纵语言`,主要是对数据进行增加、删除、修改操作。常用的语句关键字有 INSERT、UPDATE、DELETE 等。
```sql
INSERT INTO (1,2,...) values (,,...),(,,...);
UPDATE SET = WHERE ;
DELETE FROM WHERE ;
```
> ## Like
```sql
SELECT *
FROM customers
WHERE firstname LIKE '%a%';
```
- `%`:匹配任意字符(包括零个字符)。
- `_`:匹配单个字符。
# 实验二
> ## 四种连接 等值连接 自然连接 相关子查询 非相关子查询
> ## join(equal join: comma where join on) 等值连接
```sql
SELECT 1, 2, ...
FROM 1
[INNER] JOIN 2 -- INNER可省略默认就是内连接
ON 1. = 2. -- 明确分离连接条件
WHERE 1. = xxx -- 仅存放过滤条件,可读性更强
[AND 2. = xxx];
select name ,age
from role join user
on role.id=user.id
where role.name="郑笃实" and ....
-- 例子
-- 1. 老式逗号+WHERE写法
SELECT s.student_name, sc.subject, sc.score
FROM student s, score sc -- 逗号分隔两张表,给表起别名简化书写
WHERE s.student_id = sc.student_id -- 等值连接条件
AND sc.score >= 60; -- 过滤及格成绩
-- 2. 标准JOIN ON写法推荐
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc
ON s.student_id = sc.student_id -- 明确连接条件
WHERE sc.score >= 60; -- 明确过滤条件
```
> ## natural join(natural join or join using()) 自然连接
```sql
-- 2. 标准JOIN ON写法推荐必须两张表中均存在该列且列名完全一致必须两张表中均存在该列且列名完全一致
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc
USING (sc.student_id) -- 明确连接条件 -- ON s.student_id = sc.student_id
WHERE sc.score >= 60; -- 明确过滤条件
-- 其实就跟join on一样而已 只不过是 孔乙己的茴的四种写法罢了......
```
> ## corelated subquery 相关子查询
相关子查询(又称关联子查询)是**依赖外部查询的列值**才能执行的子查询,无法独立运行(子查询中会引用外部查询的表列)。
```sql
-- 需求:查询「个人成绩大于其所在班级平均成绩」的学生姓名和对应科目、成绩
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc ON s.student_id = sc.student_id
-- 外部查询的s.class_id传入子查询作为平均成绩的计算条件
WHERE sc.score > (
SELECT AVG(sc2.score) -- 子查询:计算当前学生所在班级的平均成绩
FROM score sc2
JOIN student s2 ON sc2.student_id = s2.student_id
WHERE s2.class_id = s.class_id -- 引用外部查询的s.class_id依赖外部查询
);
sql sql里面
```
> ## noncorelated subquery 非相关子查询
是**不依赖外部查询**的子查询,可以独立执行并返回一个结果集,外部查询直接使用该结果集进行后续计算,是最常用的子查询类型。
```sql
-- 需求查询“数学科目满分100分”的学生姓名
SELECT student_name
FROM student
WHERE student_id = ( -- 子查询返回单行结果时,用=匹配
SELECT student_id
FROM score
WHERE subject = '数学' AND score = 100
LIMIT 1 -- 确保子查询返回单行
);
-- 这个其实就是大多数时候 写的sql语句 (虽然工作中 一般都不这么手写原生的sql语句hhhh
```
> ## UNION 大法
有思路但是不知道这么写?
有多张表但是不知道这么写在一个sql里面
**为什么要写在一个sql里面 UNION大法帮助你**
```sql
SELECT p.model, pc.price
FROM products p
JOIN pcs pc ON pc.model = p.model
WHERE p.maker = 'B'
UNION
SELECT p.model, l.price
FROM products p
JOIN laptops l ON l.model = p.model
WHERE p.maker = 'B'
UNION
SELECT p.model, pr.price
FROM products p
JOIN printers pr ON pr.model = p.model
WHERE p.maker = 'B';
-- left join
SELECT p.model, COALESCE(pc.price, l.price, pr.price) AS price
FROM products p
LEFT JOIN pcs pc ON pc.model = p.model
LEFT JOIN laptops l ON l.model = p.model
LEFT JOIN printers pr ON pr.model = p.model
WHERE p.maker = 'B';
-- 谁最清晰一目了然
```
> ## 小tip
SELECT 分组列, 聚合函数(...)
FROM 表
WHERE 行条件
GROUP BY 分组列
HAVING 组条件(通常含聚合函数)
ORDER BY ... 排序顺序
- GROUP BY 不一定要配合having
- GROUP BY 是按照....分组 就是 类似去重了
- HAVING 就是对于这个分组的限制 一般都是
Find those makers of at least two different computers (PCs or laptops) with speeds of at least 2.80.
```sql
SELECT maker
FROM (
SELECT p.maker, p.model
FROM products p
JOIN pcs pc ON pc.model = p.model
WHERE pc.speed >= 2.80
UNION
SELECT p.maker, p.model
FROM products p
JOIN laptops l ON l.model = p.model
WHERE l.speed >= 2.80
) t
GROUP BY maker
HAVING COUNT(DISTINCT model) >= 2;
```
### 8) Find all customer's information purchased model 1001 and 1002.
(找出**同时**买过 1001 和 1002 的客户信息)
```sql
SELECT c.*
FROM customers c
JOIN sales s ON s.customer_id = c.customer_id
WHERE s.model IN ('1001', '1002')
GROUP BY c.customer_id, c.firstname, c.lastname, c.city, c.address, c.email
HAVING COUNT(DISTINCT s.model) = 2;
```
> 记忆点:`WHERE model IN (...)` 先筛两种型号,再用 `HAVING COUNT(DISTINCT model)=2` 保证“两种都买过”。
------
### 9) Find all laptops whose hard disk is greater than all PCs' hard disk.
(找出所有 laptop使其 hd **大于所有** PC 的 hd
**最稳写法(用 MAX**
```sql
SELECT *
FROM laptops
WHERE hd > (SELECT MAX(hd) FROM pcs);
```
(也可以写 ALL
```sql
SELECT *
FROM laptops
WHERE hd > ALL (SELECT hd FROM pcs);
```
------
### 10) Find all customer that not purchase any products.
(找出从未购买过任何产品的客户)
**方法1LEFT JOIN**
```sql
SELECT c.*
FROM customers c
LEFT JOIN sales s ON s.customer_id = c.customer_id
WHERE s.customer_id IS NULL;
```
**方法2NOT EXISTS**
```sql
SELECT c.*
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM sales s
WHERE s.customer_id = c.customer_id
);
```
# 实验三
> ## 触发器 Trigger
```sql
//
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name FOR EACH ROW
BEGIN
-- 觸發器執行的SQL語句
statement1;
statement2;
statement3;
END;
//
show trigger
//
drop trigger schemaName.triggerName
```
```sql
1AFTER行级触发器PCS的价格发生变化后就自动在价格变化表pcprice_log中增加一条相应记录
create trigger abbc
after update on for each row
begin
insert into log values(old.values,new.values,,,)
end
```
```sql
2AFTER行级触发器Customer中的一个顾客信息后Sales中该顾客的所有购买记录
create trigger abbb
begin DELETE on customer for each row
begin
delete from sales where contomerid=old.contomerid
end
```
```sql
3DML操作的用户进行安全检查
```
```sql
51000010%10%
create trigger asdgfsd
after insert on for each row
begin
DECLARE total_paid DECIMAL(12,2);
SELECT SUM(paid)
INTO total_paid
FROM Sales
WHERE customer_id = NEW.customer_id;
IF total_paid > 10000 THEN
UPDATE Customer
SET discount = 0.1000
WHERE customer_id = NEW.customer_id
AND discount < 0.1000;
END IF;
end
```
```sql
6"AllPaid""AllPaid"
CREATE TRIGGER trg_sales_allpaid_ins
AFTER INSERT ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END
CREATE TRIGGER trg_sales_allpaid_ins
AFTER update ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END$$
CREATE TRIGGER trg_sales_allpaid_ins
AFTER delete ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END$$
```
**关于触发器的new虚拟表格和old虚拟表格**
当进行`insert`的时候new表格可以获取插入的数据。
当进行`delete`的时候old表格可以获取被删除行的数据。
当进行`update`的时候new表格中是修改后的数据old表格中是被修改行的数据。
# 实验四
> ## 存储过程
**我们之前所学习的 MySQL 语句都是针对一个表或几个表的单条 SQL 语句,但是在数据库的实际操作中,经常会有需要多条 SQL 语句处理多个表才能完成的操作。**
**例如:** `张三工资是否大于 所属部门的平均工资` 先知道张三部门,计算平均工资,是否大于
**存储过程**是一组为了完成特定功能的 **SQL 语句集合**
- 减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)
- 减少了 SQL 语句暴露在 网上的风险,也提高了数据查询的安全性
- 简化操作提高了sql语句的重用性减少了开发程序员的压力
- 减少操作过程中的失误,提高效率
```sql
# ,SQL每个SQL需要使用 ;
# Mysql ;sql语言的结束语 BEGIN --- END 中的分号会导致声明存储过程的语法结束,报错;
# 使 DELTMITER MYSQL的结束符号 (// , Mysql的结束符号
DELIMITER //
CREATE PROCEDURE (IN|OUT|INOUT ,...)
[characteristics ...]
BEGIN
DECLARE
#
END //
# DELIMITER Mysql的结束符所以执行: END //
DELIMITER ;
# SQL ; .
# DELTMITER Mysql的结束符, ,使,Mysql默认结束符 ; ,
# Java ( ,....){ ; } .
```
| 参数类型 | 作用 | 传递方向 | 特点说明 |
| :------- | :--------------------------------- | :--------------------- | :--------------------------------------------- |
| IN | 输入参数,给存储过程传入值 | 调用时传入,过程内只读 | 过程内不能修改传入值(改变不影响调用者) |
| OUT | 输出参数,存储过程把值返回给调用者 | 过程内写,调用后拿结果 | 调用时不传值,过程内部给它赋值,调用后取出值 |
| INOUT | 输入输出参数,既传入又返回结果 | 调用时传入,过程内读写 | 过程内可以读取初始值并修改,调用结束后返回新值 |
> ## 例子
```sql
CREATE PROCEDURE selId(IN ID INt, NNAME DOUBLE) # in
BEGIN
-- SELECT * FROM employees WHERE employee_id = 100;
SELECT * FROM employees WHERE employee_id = ID;
END
#:
CALL selId(100);
#:
CALL selId('100');
#: ,...
SET @eid = 100
CALL selId(@eid);
```
> ## 存储函数
```sql
-- 存储函数 和 存储过程声明语法大致也相同,
CREATE FUNCTION ([IN] )
RETURNS
[characteristics...]
BEGIN
-- 函数体
-- 函数体中存在 RETURN 语句
END
```
- **参数列表:** 存储函数 声明比较严格,参数只能是 `IN入参` **默认也是IN 所以可以不用声明参数 IN 更加符合编程语言的规范.**
- **RETURNS** 表示存储函数的 返回类型, **存储函数只能有一个返回值. 且`必须有一个返回值.`**
- **[characteristics…]** 和存储过程一样,声明对函数内部的声明约束.
- **BEGIN…END** 和存储过程一样包含方法体,如果只有一条语句,也可以省略.
```sql
# id
DELIMITER $$
CREATE FUNCTION find(empid INT)
RETURNS VARCHAR(60)
BEGIN
DECLARE name VARCHAR(50);
SELECT CONCAT(firstname, lastname) INTO name
FROM employees
WHERE id = empid;
RETURN name;
END$$
DELIMITER ;
#
select find(123);
select find(3123);
```
> **存储函数FUNCTION不支持 `OUT / INOUT` 参数**,只能有 **`IN` 参数**(输入参数)。
```sql
# RateModel(cid, m, r)
# cid m r Ratings
# rating_time
# Products m
#number_of_ratings
#total_rating
CREATE PROCEDURE RateModel(IN cid VARCHAR(20), IN m VARCHAR(20), IN r INT)
BEGIN
DECLARE v_cnt INT;
DECLARE v_sum INT;
-- 1) 插入一条新评分(历史保留)
INSERT INTO Ratings(customer_id, model, rating_time, rating)
VALUES (cid, m, NOW(), r);
-- 2) 重新统计该型号 m 的评分次数和总分(只统计非 NULL
SELECT COUNT(rating),SUM(rating)
INTO v_cnt, v_sum
FROM Ratings
WHERE model = m AND rating IS NOT NULL;
-- 3) 更新 Products
UPDATE Products
SET number_of_ratings = v_cnt,
total_rating = IF(v_cnt = 0, NULL, v_sum)
WHERE model = m;
END
```
```sql
# DeleteRating(cid, m)
#/ cid m
# Ratings
#customer_id = cid
#model = m
#rating = NULL
# rating_time
create procedure DeleteRating(in cid int, in m varchar(50))
begin
```
# Functional Dependency and Normal Form
>请给出 **函数依赖 (Functional Dependency)** 的定义,并解释 **平凡函数依赖 (Trivial FD)****非平凡函数依赖 (Non-trivial FD)**
> 求候选码
```sql
Let relation (i.e. table) R(ABCDEFGH) have the following functional dependencies:
A B
CH A
B E
BD C
EG H
DE F
Find all keys of relation R(ABCDEFG) with functional dependencies.
#FD的所有的候选码
```
1. **先算出所有的RHS**
1. RHS就是在等号右边的 RHS={B A E C H F }
2. **所以我们要以不在RHS的字母开始 也就是C D**
3. **算{C D}+ 就是看 C D 能推出来什么 看起来什么都不能推出来 只有自己**
4. **那就算三个的 {ACD} 能推出全集 那就是 acd是一个key**
1. 然后发现BCD也是
5. **发现剩下的三位的不够了**
6. 看四位的CDGH CDEG 是
7. 最终总结u所有的candidate key 是 {ADG} {BDG} {CDGH} {CDEG}
8. 判断下面是否有冗余的
1. 邪修法门
1. L 只在左边出现过的 (包的)
2. R 只在右边出现过的 (不可能)
3. LR 两边都出现过的 (有可能成为候选码)
> 判断是否符合BCNF
```
The relation R has the attributes R(ABCD) and the functional dependencies F={AB→C, C→D, D→A}, Is the relation R in BCNF? Briefly explain your answer.
```
> 求最小依赖集

View File

@@ -0,0 +1,4 @@
- 删除boss表和admin表 改为在user表中加一个usersrole统一管理
- 新想两个表
- 前端增加删除和修改按钮
- boss可以创建岗位

View File

@@ -0,0 +1,18 @@
考试内容
- 作业
- 问答 4*5
- E-R转化模式结合
- 分析候选码
- 外码
- 函数依赖最小化 候选码 范式
- sql
- 定义
- 操作
- 控制
- 视图
- ......
- 重构语法树优化 17 Les21 Query Optimization
- 故障恢复 18 Les22 Transaction
- 并发可串行化 19 Les23 Concurrency control

View File

@@ -0,0 +1,4 @@
Semestic
AST

View File

@@ -0,0 +1,392 @@
# 知识点
好的,我将为你系统整理这四章的全部知识点,按章节顺序分解并整合核心内容、定义、图示、流程图,并汇总例题。对于每章内容,我也会根据重点举一反三地出一些典型练习题并附上解析,帮助你理解和练习。
我完成后会通知你查看结果。
# 编程题
## A
```c++
#include <bits/stdc++.h>
using namespace std;
string S[]={"main","if","else","for","while","int"};
void show(string s){
if(s[0]>='0'&&s[0]<='9')
cout << "(integer," << s << ")" << endl;
else{
int flag=0;
for(int i=0;i<6;i++){
if(s==S[i]){
flag=1;
cout<<"(keyword,"<<s<<")"<<endl;
}
}
if(flag==0)
cout<<"(identifier,"<<s<<")"<<endl;
}
}
int main()
{
string s;
while (cin >> s)
{
int len = s.length();
string a = "";
for (int i = 0; i < len; i++)
{
if (s[i] == '=' || s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '<' || s[i] == '>' || s[i] == '!')
{
if (a.length())
show(a);
a = "";
if (i + 1 < len && s[i + 1] == '=')
{
cout << "(operator," << s[i] << s[i + 1] << ")" << endl;
i++; // i+1,否则下次循环会重复判断
}
else
cout << "(operator," << s[i] << ")" << endl;
}else if(s[i]=='('||s[i]==')'||s[i]=='{'||s[i]=='}'||s[i]==','||s[i]==';'){
if(a.length())
show(a);
a="";
cout << "(boundary," << s[i] << ")" << endl;
}else
a+=s[i];
}
if(a.length())
show(a);
}
}
```
两个特殊点
- 就是分类要分好
- 通过show()函数来将a给打印出来 这样打印其他operator||boundary的时候能打印干净
## B
```C++
#include <bits/stdc++.h>
#include <regex>
using namespace std;
int main()
{
string s;
cin >> s;
regex pattern(R"(^[+-]?((\d+\.\d+)([eE][+-]?\d+)?|(\d+)[eE][+-]?\d+)$)");
cout << (regex_match(s, pattern) ? "YES\n" : "NO\n");
return 0;
}
// R"(^[\t]*[+-]?)"
// 1) 小数(两侧有数字)^[\t]* [+-]?((\d\.\d) + 可选指数 ([eE][+-]?\d)?)
// 2) 整数 + 必须指数
// R"( ^[+-]? ( (\d+\.\d+) ([eE][+-]?\d+)? | (\d+)([eE][+-]?\d+) )$ )" //^[+-]?可选正负号
//(\d+\.\d+)任意小数
//([eE][+-]?\d+)?可选指数
//(\d+)任意整数
//[eE][+-]?\d+ 必须整数
//R"(^[+-]?( (\d+\.\d+)([eE][+-]?\d+)? | (\d+)[eE][+-]?\d+ ) )"
```
## C
```c++
#include <bits/stdc++.h>
using namespace std;
struct Node {
string s1, s2;
};
Node p[101];
int var[26];
int expression(const string& s) {
if (s.length() >= 3 && (s[1] == '+' || s[1] == '>')) {
int a = s[0] - 'A';
int b = s[2] - 'A';
if (s[1] == '+') return var[a] + var[b];
else return var[a] > var[b];
}
if (s[0] == '-') return -stoi(s.substr(1));
return stoi(s);
}
int main() {
int n, max_line = 0;
string s1, s2;
memset(var, 0, sizeof(var));
while (cin >> n) {
cin >> s1;
p[n].s1 = s1;
if (s1 != "STOP") {
cin >> s2;
p[n].s2 = s2;
}
max_line = max(max_line, n); // 记录最大行号
}
for (int i = 1; i <= max_line; i++) {
if (p[i].s1.empty()) continue;
string cmd = p[i].s1, arg = p[i].s2;
if (cmd == "LET") {
int idx = arg[0] - 'A';
var[idx] = expression(arg.substr(2));
} else if (cmd == "PRINT") {
int idx = arg[0] - 'A';
cout << arg[0] << "=" << var[idx] << endl;
} else if (cmd == "GOTO") {
i = expression(arg) - 1;
} else if (cmd == "IF") {
if (!expression(arg)) i++;
} else if (cmd == "STOP") {
break;
}
}
}
```
## D
```c++
#include <bits/stdc++.h>
using namespace std;
/*
E→TG
G→+TG | ε
T→FS
S→*FS | ε
F→(E) | i
*/
void E();
void G();
void T();
void S();
void F();
int num = 0;
int idx = 0;
string s;
void E()
{
if (s[idx] == '(' || s[idx] == 'i')
{
cout << num++ << " E-->TG" << endl;
T();
G();
}
else
{
puts("error");
exit(0);
}
}
void G()
{
if (s[idx] == '+')
{
cout << num++ << " G-->+TG" << endl;
idx++;
T();
G();
}
else
{
cout << num++ << " G-->&" << endl;
}
}
void T()
{
if (s[idx] == '(' || s[idx] == 'i')
{
cout << num++ << " T-->FS" << endl;
F();
S();
}
else
{
puts("error");
exit(0);
}
}
void S()
{ // S→*FS | ε
if (s[idx] == '*')
{
cout << num++ << " S-->*FS" << endl;
idx++;
F();
S();
}
else
{
cout << num++ << " S-->&" << endl;
}
}
void F()
{
if (s[idx] == '(')
{
cout << num++ << " F-->(E)" << endl;
idx++;
E();
if (s[idx] == ')')
idx++;
else
{
cout << "error" << endl;
exit(0);
}
}
else if (s[idx] == 'i')
{
cout << num++ << " F-->i" << endl;
idx++;
}
else
{
puts("error");
exit(0);
}
}
int main()
{
cin >> s;
E();
if (s[idx] == '#')
cout << "accept" << endl;
else
cout << "error" << endl;
}
```
## E
```C++
#include <bits/stdc++.h>
using namespace std;
char s[100];
int c = 0;
int num = 1;
void E();
void T();
void G();
void F();
void S();
void E() // E→TG
{
if (s[c] == 'i' || s[c] == '(')
{
cout << num++ << " E->TG" << endl;
T();
G();
}
else
{
puts("error!");
exit(0);
}
}
// G→+TG | ε
void G()
{
if (s[c] == '+')
{
cout << num++ << " G->+TG" << endl;
c++; // 注意这里因为一s[c]一定是+ 那么下一次判断也就是
// T() 和G()判断的时候 就应该从s[c++]开始 所以c++
T();
G();
}
else if (s[c] == ')' || s[c] == '#')
{
cout << num++ << " G->^" << endl; // 只有在 FOLLOW(G) 才能走 ε
}
else
{
puts("error!");
exit(0);
}
}
void T() // T→FS
{
if (s[c] == 'i' || s[c] == '(')
{
cout << num++ << " T->FS" << endl;
F();
S();
}
else
{
cout << "error!" << endl;
exit(0);
}
}
void S() // S→*FS | ε
{
if (s[c] == '*')
{
cout << num++ << " S->*FS" << endl;
c++;
F();
S();
}
else if (s[c] == '+' || s[c] == ')' || s[c] == '#')
{
cout << num++ << " S->^" << endl; // 只有在 FOLLOW(S) 才能走 ε
}
else
{
puts("error!");
exit(0);
}
}
void F()
{
if (s[c] == 'i')
{
cout << num++ << " F->i" << endl;
c++;
}
else if (s[c] == '(')
{
cout << num++ << " F->(E)" << endl;
c++;
E();
if (s[c] == ')')
c++;
else
{
cout << "error!" << endl;
exit(0);
}
}
else
{
cout << "error!" << endl;
exit(0);
}
}
int main()
{
cin >> s;
E();
if (s[c] != '#')
cout << "error!" << endl;
else
cout << "acc!" << endl;
}
```