C++(23)--多態性與虛函數

多態性與虛函數

  • 1.靜態多態-重載
  • 2.動態多態-重寫
    • 2.1 向上轉換/向下轉換
  • 3.虛函數的工作原理
  • 4.純虛函數和抽象類
  • 5.補充項目(都市浮生記)-卒

《老九學堂C++課程》學習筆記。《老九學堂C++課程》詳情請到B站搜索《老九零基礎學編程C++入門》
-------------簡單的事情重復做,重復的事情用心做,用心的事情堅持做(老九君)---------------

多態–多種表現形式,生物學名詞。
同一個名稱的函數,可以實現不同的功能。

什么是多態
面向對象編程的多態性包括:
1.面向不同的對象發送同一條信息–多個對象調用同一個函數
2.不同的對象在接收時回產生不同的行為–
不同的行為–不同的實現,即執行不同的函數功能。函數名相同,但執行的具體細節不同。

1.靜態多態-重載

靜態多態–重載
靜態多態也叫編譯時多態。
demo1.游戲引擎調用得中類對象進行移動操作

// GameCore.h
//
// Created by 陳瑩瑩 on 2021/3/24.
//
#ifndef CHAPTER14_GAMECORE_H
#define CHAPTER14_GAMECORE_H
#include <iostream>
#include <string>
#include <vector>
#include "Hero.h"
#include "Warrior.h"
#include "Archmage.h"
/** 游戲引擎/游戲業務/游戲核心類* **/
class GameCore {
public:GameCore();~GameCore();// 定義一個函數,用來移動游戲角色// 重載--函數名相同,參數列表類型或數量不同void MoveRole(Warrior& warrior){warrior.Move();     // 實際上就是調用傳入戰士的移動方法}void MoveRole(Archmage& archmage){archmage.Move();}// 移動一批戰士void MoveRole(vector<Warrior*> vecWarrior){for(auto warrior:vecWarrior){warrior->Move();}}
};
#endif //CHAPTER14_GAMECORE_H
//main.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Hero.h"
#include "Warrior.h"
#include "Archmage.h"
#include "GameCore.h"
using namespace std;
void HeroTest();
int main() {HeroTest();return 0;
}void HeroTest(){Hero hero("布衣");Warrior warrior1("呂布1",50);Warrior warrior2("呂布2",50);Warrior warrior3("呂布3",50);Archmage archmage("甘道夫",80);GameCore gamecore;
//    gamecore.MoveRole(warrior);
//    gamecore.MoveRole(archmage);vector<Warrior *> vecWarrior;vecWarrior.push_back(&warrior1);vecWarrior.push_back(&warrior2);vecWarrior.push_back(&warrior3);// 主要觀察,調用游戲業務方法來統一操作傳入的多個戰士gamecore.MoveRole(vecWarrior);}

輸出

調用了Hero 四個參數版本的構造
調用了Hero 一個參數版本的構造
調用了Hero 四個參數版本的構造
調用了Hero 四個參數版本的構造
調用了Hero 四個參數版本的構造
調用了Hero 四個參數版本的構造
戰士《呂布1》背著一大堆近戰武器正在前進。。。
戰士《呂布2》背著一大堆近戰武器正在前進。。。
戰士《呂布3》背著一大堆近戰武器正在前進。。。

2.動態多態-重寫

動態多態–重寫
動態多態也叫運行時多態,函數在執行的過程中才能確定要執行的是哪一個。

父類方法中加virtual關鍵字,在核心引擎類中的RoleMove參數使用hero 對象,那么可以給RoleMove傳遞各種hero子類實現各種移動。

//mian.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Hero.h"
#include "Warrior.h"
#include "Archmage.h"
#include "GameCore.h"
#include "Assassin.h"
using namespace std;
void HeroTest();
int main() {HeroTest();return 0;
}void HeroTest(){Hero hero("布衣");Warrior warrior1("呂布1",50);Warrior warrior2("呂布2",50);Warrior warrior3("呂布3",50);Archmage archmage("甘道夫",80);GameCore gamecore;// 不使用virtual 關鍵字的效果// 編譯器就會根據當前對象的類型,調用類型中定義的move 方法gamecore.MoveRole(warrior1);gamecore.MoveRole(archmage);// 使用virtual 關鍵字,派生類重寫了基類的方法//不使用virtual 輸出// 普通英雄呂布1正在奔跑在艾澤拉斯大陸上// 普通英雄甘道夫正在奔跑在艾澤拉斯大陸上//使用virtual 輸出// 戰士《呂布1》背著一大堆近戰武器正在前進。。。// 大法師甘道夫為了節省魔法, 只好用雙腳趕路// 不修改核心邏輯,直接傳入新類型對象Assassin assa("飛檐走壁",100);gamecore.MoveRole(assa);
}

新增的刺客類

// Assassin.h
//
// Created by 陳瑩瑩 on 2021/3/25.
//#ifndef CHAPTER14_ASSASSIN_H
#define CHAPTER14_ASSASSIN_H
#include <iostream>
#include <string>
#include "Hero.h"
using namespace std;
/** 體會程序是如何進行升級的* 假定游戲需要增加一個新的職業:刺客,但是核心業務類肯定不能夠隨便修改*/class Assassin:public Hero{
public:Assassin();Assassin(const string& nickName, int power):Hero(nickName),m_Power(power){}void Move() override{cout << "隱藏在黑暗中的刺客" << GetNickName() << "正在偷偷地潛入一座宮殿"<< endl;}~Assassin();
private:int m_Power;};#endif //CHAPTER14_ASSASSIN_H
//Assassin.h
//
// Created by 陳瑩瑩 on 2021/3/25.
//#include "Assassin.h"Assassin::Assassin() {}
Assassin::~Assassin(){}

2.1 向上轉換/向下轉換

    // 為了能夠讓同一個函數操作不同類型的子類對象,所以我們把參數類型定義成基類對象// 當傳遞Hero類型的子類型時,參數類型可以自動轉換// 關于向上和向下轉換// 當B是A的子類型(class B: public A ),意味著所有對A對象的操作都可以對B對象進行// 即B重用A的操作來實現自己的操作// 向上轉型:把子類型對象轉換為父類型對象,下面有三個注意點:// 1.向上轉型是安全的// 2.向上轉型是自動完成的(自動類型轉換)// 3.向上轉型的過程中,會丟失子類型的信息。// Warrior warrior;         // 子類型對象// Hero& hero = warrior;    // 父類型引用指向了子類型對象--向上轉型// hero.XiaoQuanQuan();     // 編譯器會報錯--丟失了子類型信息// 如果還想使用子類型方法,那么就需要再進行強制類型轉換--向下轉型// warrior& newWarrior = (Warrior&)hero;   // 向下轉型不安全// hero對象有可能是父類型的另一個子類型// Archmage warrior;// Hero& hero = warrior;// Warrior& newWarrior = (Warrior&)hero; // 編譯時不會報錯,但是執行時會報錯,(老師演示的時候還能夠運行的)

3.虛函數的工作原理

1.構造函數不能是虛函數
2.析構函數應該定義成虛函數,除非該類不做基類。為了安全起見,為將類的析構函數定義為虛函數。
3.友元函數不能是虛函數。

虛函數的工作原理:會為父類對象構建一個隱藏成員,為指向虛函數表的指針。子類重寫了父類方法的話,也會為子類對象構建一個隱藏成員,為指向虛函數表的指針。但是具體的函數指針變了的。
在這里插入圖片描述
demo1:觀察虛函數列表地址的變化(實驗現象沒有實現

//mian.cpp
void VirtualPointTest(){
//    Base base;      // 基類對象
//    long* baseAdress = (long*) &base;   // 轉換成長整形指針,方便待會指針移動和轉換
//    // cout << "基類對象地址" << &base << endl;
//    cout << "基類對象地址" << baseAdress << endl;
//    long* virTablePtr = (long*)(baseAdress + 0);    // 虛函數表的地址就是這么求的
//    cout << "虛函數表的地址:" << virTablePtr << endl;
//    long* virFunctionPtr1 = (long*) *(virTablePtr + 0);
//    cout << "虛函數表中第一個虛函數的地址" << virFunctionPtr1 << endl;
//    long* virFunctionPtr2 = (long*) *(virTablePtr + 1);
//    cout << "虛函數表中第一個虛函數的地址" << virFunctionPtr1 << endl;
//    long* virFunctionPtr3 = (long*) *(virTablePtr + 2);
//    cout << "虛函數表中第一個虛函數的地址" << virFunctionPtr1 << endl;Base base;      // 基類對象int* baseAdress = (int*)&base;            // 基類對象cout << "基類對象地址" << baseAdress << endl; // 保存基類對象的地址int* virTablePtr = (int*)*(baseAdress + 0); //虛擬表的指針地址cout << "基類隱藏成員:虛擬表的指針地址:" << virTablePtr << endl;
//    // 虛擬表中第一個虛函數的地址
//    int* virFunctionPtr = (int*) *(virTablePtr + 0);
//    cout << "虛擬表中第一個虛函數的地址:" << virFunctionPtr << endl;   //沒輸出成功呀
//    cout << "end" << endl;
//    //強制轉換成函數來調用
//    void(*BaseVirtual1)() = (void(*)())virFunctionPtr;
//    BaseVirtual1();                                 // 取出第一個虛函數后調用。
//    // 下面注意:GCC mingW64 指針+ 2,如果使用的是VS20xx版本,指針需要加1, mac gcc +2
//    int* virFunctionPtr2 = (int*) *(virTablePtr + 2);
//    void(*BaseVirtual2)() = (void(*)())virFunctionPtr2;
//    BaseVirtual2();                                 // 取出第一個虛函數后調用。
//    int* virFunctionPtr3 = (int*) *(virTablePtr + 4);
//    void(*BaseVirtual3)() = (void(*)())virFunctionPtr3;
//    BaseVirtual3();                                 // 取出第一個虛函數后調用。// 取出第一私有成員cout << "第一個私有成員member的值:" << *(baseAdress + 2) << endl;  // 9527 取處出來了cout << "---------- 派生類對象的內存信息如下----------------" << endl;Son son;int* sonAdress = (int*)&son;cout << "派生類對象的地址:" << sonAdress << endl;virTablePtr = (int*)*(sonAdress + 0);cout << "派生類對象的虛擬表的地址:" << virTablePtr << endl;// 有三個虛函數,一個被覆蓋了(地址變了),其余兩個沒有變。
}
// VirtualPointDemo1.h
//
// Created by 陳瑩瑩 on 2021/3/27.
//
#ifndef CHAPTER14_VIRTUALPOINTDEMO1_H
#define CHAPTER14_VIRTUALPOINTDEMO1_H
#include <iostream>
#include <string>
using namespace std;
class Base {
private:int menber;
public:Base(){menber = 9527;}virtual void baseVirtual1(){cout << "基類中的虛函數版本1"<<endl;}virtual void baseVirtual2(){cout << "基類中的虛函數版本2"<<endl;}virtual void baseVirtual3(){cout << "基類中的虛函數版本3"<<endl;}
};class Son :public Base{
public:void baseVirtual2() override{cout << "派生類中唯一實現的2版本的基類虛函數" << endl;}
};#endif //CHAPTER14_VIRTUALPOINTDEMO1_H

4.純虛函數和抽象類

抽象類–天生的父類,實例出來沒啥用,需要進行擴展。(生物對象:血量,攻擊力)

語法上一個抽象類無法被實例化

抽象類的虛函數都為純虛函數,純虛函數讓基類函數沒有函數體,在基類中不能被調用。純虛函數必須有派生類來實現純虛函數體的功能。(一個類如果有一個純虛函數,那么這個類就是抽象類)

純虛函數語法格式

virtual 返回類型 函數名(參數列表) const=0;

demo:多態的方式來模擬“星際爭霸”中的指揮官和各種兵種之間的互動關系。
指揮官發出指令–Rolling Thunder,各單位發起進攻

//mian.cpp
#include <iostream>
#include <vector>
#include "AbstractClass.h"void AbstractTest();
int main() {AbstractTest();return 0;
}void AbstractTest(){// 嘗試實例化一個抽象類類// BattleUnit battleUnit;   提示是一個抽象類不能被實例化// 沒有重載全部虛函數,子類還是會被認為是抽象類Marin marin1("巫妖王");Marin marin2("死亡騎士");marin1.Fight(marin2);SiegeTank tank1("坦克1");tank1.Move(10,20);Viking viking1("北歐海盜");vector<BattleUnit*> units;units.push_back(&marin1);units.push_back(&marin2);units.push_back(&tank1);units.push_back(&viking1);Commander commander;cout << "讓指揮官移動多個不同類型的戰斗單位" << endl;commander.Move(units,50,50);
}
//AbstractClass.h
//
// Created by 陳瑩瑩 on 2021/4/2.
//
#ifndef STAR_WAR_ABSTRACTCLASS_H
#define STAR_WAR_ABSTRACTCLASS_H
#include <iostream>
#include <string>
#include <vector>
using namespace std;
/** 實現一個簡單版的星際爭霸游戲,用來加深對多態及抽象類的理解* */
class Point{
private:int m_x;int m_y;
public:Point(){}Point(int _x, int _y):m_x(_x),m_y(_y){}int GetX() {return m_x;}int GetY() {return m_y;}void SetX(int x) {this->m_x = x;}void SetY(int y) {this->m_y = y;}friend ostream& operator << (ostream& out, const Point& p){out << "(" << p.m_x << "," << p.m_y << ")" << endl;return out;}
};class BattleUnit{// 戰斗單位了
private:
protected:string name;int maxHp;int currHp;Point position;int attDistance;    // 當前對象的攻擊距離
public:BattleUnit(){}BattleUnit(const string& _name): name(_name){maxHp = 100;currHp = 100;position.SetX(0);position.SetY(0);attDistance = 100;}// 設置某個方法分為純虛函數,Battle類變成抽象類,不能實例化virtual void Fight(BattleUnit& other) = 0;virtual void Move(int x, int y) = 0;virtual void Move(Point& position) = 0;const string & GetName() const{return name;}
};
// 我們可以提供抽象的基類純虛方法的默認實現
void BattleUnit::Fight(BattleUnit& other){// 每個單位進行對戰前,依據當前坐標計算兩個單位間的距離// 如果距離超過的攻擊距離,攻擊失敗。cout << name << "正在攻擊另一個戰斗單位:" << other.GetName() << endl;
}
void BattleUnit::Move(int x, int y){position.SetX(x);position.SetX(y);
}class Marin:public BattleUnit{
public:Marin(){}Marin(const string& _name):BattleUnit(_name){}void Fight(BattleUnit& other) override;void Move(int x, int y){BattleUnit::Move(x,y);cout << "陸戰隊員接到命令,立即前往坐標點: " << position << endl;}void Move(Point& position){}
};
void Marin::Fight(BattleUnit& other){// 在子類中調用父類的同名方法,需要使用到域運算符BattleUnit :: Fight(other);cout << "陸戰隊員" << GetName() << "正在攻擊敵人:" << other.GetName() << endl;
}class SiegeTank : public BattleUnit{
public:SiegeTank(){}SiegeTank(const string& _name) : BattleUnit(_name){}// undifined reference to "Vtable" for SiegeTank // 沒有實現完全父類的純虛函數void Fight(BattleUnit& other) override{}void Move(int x, int y)override{position.SetX(x);position.SetY(y);cout << "工程坦克" << GetName() << "收到移動命令:" << position << endl;}void Move(Point& position)override{}
};
class Viking : public BattleUnit{
public:Viking(){}Viking(const string& _name) : BattleUnit(_name){}void Fight(BattleUnit& other) override{}void Move(int x, int y)override{position.SetX(x);position.SetY(y);cout << "維京戰機" << GetName() << "立即飛往坐標:" << position << endl;}void Move(Point& position)override{}
};class Commander{// 游戲中的核心業務類,引擎
public:// 模擬了指揮官的rolling thunder// 一個指揮官同時移動了多個戰斗單位void Move(vector<BattleUnit*> units, int x, int y){for(auto unit : units){unit->Move(x,y);}}
};
#endif //STAR_WAR_ABSTRACTCLASS_H

5.補充項目(都市浮生記)-卒

window 編程呀,mac 的頭文件都引入不了

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444764.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444764.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444764.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何在Appscale下發布自己的應用(一)

本篇文章主要講如何在本地搭建appscale環境。由于國內的信息資源有限&#xff0c;很多重要的論壇被墻了&#xff0c;所以遇到不少麻煩&#xff0c;由于最近一段時間vpn也被封掉了&#xff0c;我只能通過特殊渠道方法來翻墻查閱資料&#xff0c;走了不少彎路。 1.先說系統和環境…

總結了線程安全性的二十四個精華問題

1、對象的狀態&#xff1a;對象的狀態是指存儲在狀態變量中的數據&#xff0c;對象的狀態可能包括其他依賴對象的域。在對象的狀態中包含了任何可能影響其外部可見行為的數據。 2、一個對象是否是線程安全的&#xff0c;取決于它是否被多個線程訪問。這指的是在程序中訪問對象的…

如何在Appscale下發布自己的應用(二)

本文開始講如何發布自己的app應用到appscle上 建好appscle網站后&#xff0c;可以在命令行通過 appscle deploy apppathname 來發布自己應用。 除了用命令行提交應用之外&#xff0c;還可以通過appscale的網站直接提交&#xff0c;選擇 upload application->選擇上傳文件-&g…

Python模塊(7)-SciPy 簡易使用教程

SciPy 簡易使用教程1. 符號計算2. 函數向量化3. 波形處理scipy.signal3.1 濾波器3.2 波峰定位基于numpy的一個高級模塊&#xff0c;為數學&#xff0c;物理&#xff0c;工程等方面的科學計算提供無可替代的支持。 做重要的思想是&#xff1a;符號計算和函數向量化 1. 符號計算…

Xcode的Architectures和Valid Architectures的區別

目錄[-] Xcode的Architectures和Valid Architectures的區別 Architectures Valid Architectures 原因解釋如下&#xff1a; 參考1&#xff1a; 所有IOS設備詳情列表 List of iOS devices - Wikipedia, the free encyclopedia 參考2&#xff1a; iOS 7: 如何為iPhone 5S編譯64位…

Python模塊(8)-sklearn 簡易使用教程

sklearn 簡易使用教程1.scikit-learn的數據集2.scikit-learn 的訓練和預測scikit-learn 是在Numpy,SciPy,Matplotlib三個模塊上編寫的&#xff0c;數據挖掘和數據分析的一個簡單有效的工具。scikit-learn包括6大功能&#xff1a;分類&#xff0c;回歸&#xff0c;聚類&#xff…

如何發布GAE的應用(一)

安裝googleSDK的環境&#xff1a; 1 下載安裝包從官網下載 https://cloud.google.com/sdk/downloads -> https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-170.0.0-windows-x86_64-bundled-python.zip 2 如果本地安裝了python&#xff0c;直…

leetcode887 雞蛋掉落

你將獲得 K 個雞蛋&#xff0c;并可以使用一棟從 1 到 N 共有 N 層樓的建筑。 每個蛋的功能都是一樣的&#xff0c;如果一個蛋碎了&#xff0c;你就不能再把它掉下去。 你知道存在樓層 F &#xff0c;滿足 0 < F < N 任何從高于 F 的樓層落下的雞蛋都會碎&#xff0c;…

Docker 的日志相關整理

1 Docker daemon日志的位置 Docker daemon日志的位置&#xff0c;根據系統不同各不相同。 Ubuntu - /var/log/upstart/docker.logBoot2Docker - /var/log/docker.logDebian GNU/Linux - /var/log/daemon.logCentOS - /var/log/daemon.log | grep dockerFedora - journalctl -u…

PaperNotes(15)-圖神經網絡、PyG極簡版入門筆記

圖神經網絡概況1.GNN,GCN,GE的區別2.圖卷積的通式--矩陣該如何作用2.1實現12.2實現22.3實現33.PyTorch geometric3.1 PyG內置數據集3.1.1ENZYMES dataset3.1.2Cora3.2 PyG自定義數據集3.2.1Data構建簡單的圖結構3.2.2 Dataset3.2.3 InMemoryDataset一文讀懂圖卷積GCN(https://z…

leetcode76 最小覆蓋子串

給你一個字符串 S、一個字符串 T&#xff0c;請在字符串 S 里面找出&#xff1a;包含 T 所有字母的最小子串。 示例&#xff1a; 輸入: S "ADOBECODEBANC", T "ABC" 輸出: "BANC" 說明&#xff1a; 如果 S 中不存這樣的子串&#xff0c;則返…

Unity的匹配系統

這個匹配系統是指一個玩家&#xff0c;可以創建一個自己隨意命名的房間&#xff0c;然后其他玩家可以通過聯網去搜索房間&#xff0c;然后加入房間一起游戲 我先講講怎么使用這個匹配系統&#xff1a; 在運行游戲后&#xff0c;因為添加了Network Manager HUD組件&#xff0c;所…

PaperNotes(16)-圖神經網絡GNN簡史、不動點建模-筆記

圖神經網絡簡史、簡介1.圖神經網絡簡史2.圖神經網絡--學習過程3.圖神經網絡--理論基礎4.圖神經網絡的局限5.GNN,RNN,GGNN6.小結閱讀筆記&#xff1a;從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (一)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Matchmaker

Unity的多玩家網絡功能包含了玩家在因特網上互相玩而不需要公共IP地址的服務。用戶可以創建游戲,獲取活動游戲列表;加入并退出游戲。當在internet上玩時,網絡流量將通過云中的Unity,而不是直接在客戶端之間進行。這就避免了防火墻和NATs的問題,幾乎可以在任何地方玩游戲。 …

PaperNotes(17)-圖卷積神經網絡GCN-筆記

圖卷積神經網絡GCN-筆記1.卷積是什么2.圖卷積的源起3.空域卷積3.1消息傳遞網絡MPNN3.2 圖采樣與聚合GraphSage4.頻域卷積5.圖結構的序列化-Patch-SAN從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (二)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 標簽

摘錄某個工程的 web.xml 文件片段&#xff1a;訪問順序為1—>2—>3—>4&#xff0c;其中2和3的值必須相同。 url-pattern 標簽中的值是要在瀏覽器地址欄中輸入的 url&#xff0c;可以自己命名&#xff0c;這個 url 訪問名為 servlet-name 中值的 servlet&#xff0c;兩…

leetcode236 二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。 百度百科中最近公共祖先的定義為&#xff1a;“對于有根樹 T 的兩個結點 p、q&#xff0c;最近公共祖先表示為一個結點 x&#xff0c;滿足 x 是 p、q 的祖先且 x 的深度盡可能大&#xff08;一個節點也可以是它自己的…

Unity的 UNet組件介紹

UNet常見概念簡介 Spawn:簡單來說,把服務器上的GameObject,根據上面的NetworkIdentity組件找到對應監視連接,在監視連接里生成相應的GameObject.Command:客戶端調用,服務器執行,這樣客戶端調用的參數必需要UNet可以序列化,這樣服務器在執行時才能把參數反序列化。需要注意…

MachineLearning(10)-聚類

聚類1.K-mean2.系統聚類3.DBSCAN聚類算法聚類&#xff1a;無監督學習&#xff0c;將相似的樣本聚為一類。核心如何定義相似。分類&#xff1a;有監督學習&#xff0c;依據分類準則&#xff0c;將樣本劃分為不同的類。核心分類器的設計&#xff08;KNN&#xff09;聚類&#xff…

幀同步和狀態同步(一)

幀同步 什么是幀同步&#xff1a;幀同步常被RTS(即時戰略)游戲常采用。在游戲中同步的是玩家的操作指令&#xff0c;操作指令包含當前的幀索引。一般的流程是客戶端上傳操作到服務器&#xff0c; 服務器收到后并不計算游戲行為&#xff0c; 而是轉發到所有客戶端。這里最重要的…