C++學習之路,從0到精通的征途:繼承

目錄

一.繼承的概念及定義

1.繼承的概念

2.繼承的定義

(1)繼承的定義格式

(2)繼承基類成員訪問方式的變化

二.基類與派生類間的轉換

1.派生類對象賦值給基類的引用/指針

2. 派生類對象直接賦值給基類對象

三.繼承的作用域

四.派生類的默認成員函數

1.構造函數

2.拷貝構造函數

3.賦值重載?

4.析構函數

基類與派生類的行為總結:

?編輯實現一個不能被繼承的類

五.繼承與友元

六.繼承與靜態成員

七.多繼承與菱形繼承問題

1.繼承模型

2.虛繼承

八.繼承與組合


一.繼承的概念及定義

1.繼承的概念

????????繼承(inheritance)機制是面向對象程序設計使代碼可以復?的最重要的手段,它允許我們在保持原有類特性的基礎上進行擴展,增加方法(成員函數)和屬性(成員變量),這樣產生新的類,稱派生類。

????????繼承呈現了面向對象程序設計的層次結構,體現了由簡單到復雜的認知過程。以前我們接觸的函數層次的復用,繼承是類設計層次的復用。

? ? ? ? 舉例:

? ? ? ? 如果一個人具有名字,性別,年齡等屬性,我們將這個集合定義為Person類,當我們還想要定義一個Student類時,由于Student與Person屬于“has-a”的關系,即除了Student自身的特性外,其也具有Person的所有特性時,我們可以將Student定義為Person的派生類,即Student類繼承Person類,在理解上,可以認為Student就是一個Person。

2.繼承的定義

(1)繼承的定義格式

????????下面我們看到Person是基類,也稱作父類。Student是派生類,也稱作子類:

? ? ? ? 舉例:

class Person
{
public:// 進入校園/圖書館/實驗室刷二維碼等身份認證void identity(){cout << "void identity()" << _name << endl;}
protected:string _name = "張三"; // 姓名string _address; // 地址string _tel; // 電話int _age = 18; // 年齡
};class Student : public Person
{
public:// 學習void study(){// ...}
protected:int _stuid; // 學號
};int main()
{Person p;Student s;return 0;
}

? ? ? ? 在監視窗口中可以看到Student類繼承了Person類的成員變量與成員函數。?

(2)繼承基類成員訪問方式的變化

? ? ? ? 三種繼承方式與三種訪問限定符對應著9種訪問方式:

類成員/繼承方式public繼承protected繼承private繼承
基類的public成員派生類的public成員派生類的protected成員派生類的private成員
基類的protected成員派生類的protected成員派生類的protected成員派生類的private成員
基類的private成員在派生類種不可見在派生類種不可見在派生類種不可見

<1>基類private成員在派生類中無論以什么方式繼承都是不可見的。這里的不可見是指基類的私有成員還是被繼承到了派生類對象中,但是語法上限制派生類對象不管在類里面還是類外面都不能去訪問它。

<2>基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected。可以看出保護成員限定符是因繼承才出現的。

<3>實際上面的表格我們進行一下總結會發現,基類的私有成員在子類都是不可見。基類的其他成員在子類的訪問方式 == Min(成員在基類的訪問限定符,繼承方式),public > protected > private。

<4>使用關鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過 最好顯示的寫出繼承方式。

<5>在實際運用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因為protetced/private繼承下來的成員都只能在派生類的類里面使用,實際中擴展維護性不強。

二.基類與派生類間的轉換

1.派生類對象賦值給基類的引用/指針

????????public繼承的派生類對象可以賦值給基類的指針/基類的引?。這里有個形象的說法叫切片或者切割。寓意把派生類中基類那部分切出來,基類指針或引用指向的是派生類中切出來的基類那部分。

class Person
{
protected:string _name; // 姓名string _sex; // 性別int _age; // 年齡
};class Student : public Person
{
public:int _No; // 學號
};int main()
{Student sobj;// 派生類對象可以賦值給基類的指針/引用Person* pp = &sobj;Person& rp = sobj;return 0;
}

2. 派生類對象直接賦值給基類對象

? ? ? ? 這里是基類的賦值重載實現的,本質還是進行了切片,但是基類對象不能賦值給派生類對象。

Person pobj = sobj;

三.繼承的作用域

<1>在繼承體系中基類和派生類都有獨立的作用域。

<2>派生類和基類中有同名成員,派生類成員將屏蔽基類對同名成員的直接訪問,這種情況叫隱藏。(在派生類成員函數中,可以使用基類::基類成員顯式訪問)

class Person
{
protected:string _name = "?李"; // 姓名int _num = 111; // 身份證號
};class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份證號:" << Person::_num << endl; // 顯式訪問cout << " 學號:" << _num << endl; // 構成隱藏}
protected:int _num = 999; // 學號
};int main()
{Student s1;s1.Print();return 0;
};

<3>需要注意的是如果是成員函數的隱藏,只需要函數名相同就構成隱藏。

class A
{
public:void fun(){cout << "func()" << endl;}
};class B : public A
{
public:void fun(int i){cout << "func(int i)" << i << endl;}
};int main()
{B b;b.fun(10); // 調用fun(int i)//b.fun(); // 基類與派生類的函數名相同,fun構成隱藏,由于沒有傳參,直接報錯return 0;
};

<4>注意在實際中在繼承體系里面最好不要定義同名的成員。

四.派生類的默認成員函數

????????6個默認成員函數,默認的意思就是指我們不寫,編譯器會變我們自動生成一個,那么在派生類中,這幾個成員函數是如何生成的呢?

1.構造函數

? ? ? ? 在初始化屬于基類的那一部分成員時,可以將所屬于基類的成員整體當作一個自定義類型派生類的構造函數必須調用基類的構造函數初始化基類的那一部分成員。如果基類沒有默認的構造函數,則必須在派生類構造函數的初始化列表階段顯式調用。

class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}
protected:int _num; //學號
};int main()
{Student s1("jack", 18);return 0;
}

? ? ? ? 同時在監視窗口中也可以看到派生類對象初始化先調用基類構造再調派生類構造。?

? ? ? ? 派生類對象構造順序:

基類成員 > 派生類成員

2.拷貝構造函數

????????派生類的拷貝構造函數必須調用基類的拷貝構造完成基類的拷貝初始化。

class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s) // 切片,調用基類的拷貝構造, _num(s._num){cout << "Student(const Student& s)" << endl;}
protected:int _num; //學號
};int main()
{Student s1("jack", 18);Student s2(s1);return 0;
}

3.賦值重載?

????????派生類的operator=必須要調用基類的operator=完成基類的復制。需要注意的是派生類的 operator=隱藏了基類的operator=,所以顯式調用基類的operator=,需要指定基類作用域。

class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s) // 切片,調用基類的拷貝構造, _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){cout << "Student& operator=(const Student& s)" << endl;if (this != &s){// 構成隱藏,所以需要顯式調用,若不顯式調用則會調用派生類的復制重載,形成死遞歸Person::operator=(s); // 賦值所屬基類的一部分_num = s._num;}return *this;}
protected:int _num; //學號
};int main()
{Student s1("jack", 18);Student s2(s1);Student s3("rose", 17);s1 = s3;return 0;
}

4.析構函數

????????派生類的析構函數會在被調用完成后自動調用基類的析構函數清理基類成員。因為這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。

????????派生類對象析構清理先調用派生類析構再調基類的析構。

class Person
{
public:Person(const char* name = "peter"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num): Person(name), _num(num){cout << "Student()" << endl;}Student(const Student& s): Person(s), _num(s._num){cout << "Student(const Student& s)" << endl;}Student& operator = (const Student& s){cout << "Student& operator= (const Student& s)" << endl;if (this != &s){// 構成隱藏,所以需要顯?調?Person::operator =(s);_num = s._num;}return *this;}~Student(){cout << "~Student()" << endl;}// 自動調用基類的析構函數
protected:int _num; //學號
};int main()
{Student s1("jack", 18);return 0;
}

? ? ? ? 在輸出中可以看到,在派生類的析構函數執行完后會自動調用基類的析構函數,所以在派生類的析構函數中不需要再對基類的那一部分資源進行析構,否則會導致同一塊資源二次釋放,只需要釋放派生類自己申請的資源即可。?

派生類對象析構順序:

派生類成員 > 基類成員

基類與派生類的行為總結:



實現一個不能被繼承的類

方法1:基類的構造函數私有,派生類的構成必須調用基類的構造函數,但是基類的構成函數私有化以后,派生類看不見就不能調用了,那么派生類就無法實例化出對象。

方法2:C++11新增了?個final關鍵字,final修改基類,派生類就不能繼承了。

// C++11的方法
class Base final
{
public:void func5() { cout << "Base::func5" << endl; }
protected:int a = 1;
private:// C++98的方法/*Base(){}*/
};class Derive :public Base
{void func4() { cout << "Derive::func4" << endl; }
protected:int b = 2;
};int main()
{Base b;Derive d;return 0;
}

五.繼承與友元

????????友元關系不能繼承,也就是說基類友元不能訪問派生類私有和保護成員 。

class Student; // 前置聲明class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name; // 姓名
};class Student : public Person
{
protected:int _stuNum; // 學號
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl; 
}int main()
{Person p;Student s;// 編譯報錯:error C2248: “Student::_stuNum”: 無法訪問 protected 成員// 解決方案:Display也變成Student 的友元即可Display(p, s);return 0;
}

六.繼承與靜態成員

????????基類定義了static靜態成員,則整個繼承體系里面只有一個這樣的成員。無論派生出多少個派生類,都只有一個static成員實例。

class Person
{
public:string _name;static int _count; // 在類內聲明
};// 在類外定義
int Person::_count = 0;class Student : public Person
{
protected:int _stuNum;
};int main()
{Person p;Student s;// 這里的運行結果可以看到非靜態成員_name的地址是不?樣的// 說明派生類繼承下來了,父類與派生類對象各有?份cout << &p._name << endl;cout << &s._name << endl;// 這里的運行結果可以看到靜態成員_count的地址是?樣的// 說明派生類和基類共用同一份靜態成員cout << &p._count << endl;cout << &s._count << endl;// 公有的情況下,?派生類指定類域都可以訪問靜態成員cout << Person::_count << endl;cout << Student::_count << endl;return 0;
}

七.多繼承與菱形繼承問題

1.繼承模型

<1>單繼承:一個派生類只有一個直接基類時稱這個繼承關系為單繼承。

<2>多繼承:一個派生類有兩個或以上直接基類時稱這個繼承關系為多繼承,多繼承對象在內存中的模型是,先繼承的基類在前面,后面繼承的基類在后面,派生類成員在放到最后面。

<3>菱形繼承:菱形繼承是多繼承的?種特殊情況。菱形繼承的問題,從下面的對象成員模型構造,可以看出菱形繼承有數據冗余和二義性的問題,在Assistant的對象中Person成員會有兩份。支持多繼承就一定會有菱形繼承,像Java就直接不支持多繼承,規避掉了這里的問題,所以實踐中也是不建議設計出菱形繼承這樣的模型的。

?

class Person
{
public:string _name; // 姓名
};class Student : public Person
{
protected:int _num; //學號
};class Teacher : public Person
{
protected:int _id; // 職工編號
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};int main()
{// 編譯報錯:error C2385: 對“_name”的訪問不明確Assistant a;a._name = "peter";// 需要顯式指定訪問哪個基類的成員可以解決二義性問題,但是數據冗余問題無法解決a.Student::_name = "xxx";a.Teacher::_name = "yyy";return 0;
}

?? ? ? ? 那么如何讓解決菱形繼承中存在的數據冗余二義性的問題呢,這里可以通過虛繼承來進行解決。

2.虛繼承

? ? ? ? 實現虛繼承的方式就是在派生類的繼承方式前加一個關鍵字virtual。

class Person
{
public:string _name; // 姓名/*int _tel;int _age;string _gender;string _address;*/// ...
};// 使用虛繼承Person類
class Student : virtual public Person
{
protected:int _num; //學號
};// 使用虛繼承Person類
class Teacher : virtual public Person
{
protected:int _id; // 職工編號
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};int main()
{// 使用虛繼承,可以解決數據冗余和二義性Assistant a;a._name = "peter";return 0;
}

八.繼承與組合

<1>?public繼承是一種is-a的關系。也就是說每個派生類對象都是一個基類對象。

<2>組合是一種has-a的關系。假設B組合了A,每個B對象中都有一個A對象。

<3>繼承允許你根據基類的實現來定義派生類的實現。這種通過生成派生類的復用通常被稱為白箱復用?(white-box reuse)。術語“白箱”是相對可視性而言:在繼承方式中,基類的內部細節對派生類可見?。繼承一定程度破壞了基類的封裝,基類的改變,對派生類有很大的影響。派生類和基類間的依賴關系很強,耦合度高。

<4>對象組合是類繼承之外的另一種復用選擇。新的更復雜的功能可以通過組裝或組合對象來獲得。對象組合要求被組合的對象具有良好定義的接口。這種復用風格被稱為黑箱復用(black-box reuse),因為對象的內部細節是不可見的。對象只以“黑箱”的形式出現。 組合類之間沒有很強的依賴關系,耦合度低。優先使用對象組合有助于你保持每個類被封裝。

<5>優先使用組合,而不是繼承。實際盡量多去用組合,組合的耦合度低,代碼維護性好。不過也不太那么絕對,類之間的關系就適合繼承(is-a)那就用繼承,另外要實現多態,也必須要繼承。類之間的關系既適合用繼承(is-a)也適合組合(has-a),就用組合。

// Tire(輪胎)和Car(車)更符合has-a的關系
class Tire {
protected:string _brand = "Michelin"; // 品牌size_t _size = 17; // 尺寸
};class Car {
protected:string _colour = "白色"; // 顏色string _num = "ABIT00"; // 車牌號Tire _t1; // 輪胎Tire _t2; // 輪胎Tire _t3; // 輪胎Tire _t4; // 輪胎
};class BMW : public Car {
public:void Drive() { cout << "好開-操控" << endl; }
};// Car和BMW/Benz更符合is-a的關系
class Benz : public Car {
public:void Drive() { cout << "好坐-舒適" << endl; }
};template<class T>
class vector
{};// stack和vector的關系,既符合is-a,也符合has-a
template<class T>
class stack : public vector<T>
{};template<class T>
class stack
{
public:vector<T> _v;
};int main()
{return 0;
}

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

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

相關文章

用vue和go實現登錄加密

前端使用CryptoJS默認加密方法&#xff1a; var pass CryptoJS.AES.encrypt(formData.password, key.value).toString()使用 CryptoJS.AES.encrypt() 時不指定加密模式和參數時&#xff0c;CryptoJS 默認會執行以下操作 var encrypted CryptoJS.AES.encrypt("明文&quo…

React百日學習計劃——Deepseek版

階段一&#xff1a;基礎鞏固&#xff08;1-20天&#xff09; 目標&#xff1a;掌握HTML/CSS/JavaScript核心語法和開發環境搭建。 每日學習內容&#xff1a; HTML/CSS&#xff08;1-10天&#xff09; 標簽語義化、盒模型、Flex布局、Grid布局、響應式設計&#xff08;媒體查詢…

WPF中如何自定義控件

WPF自定義控件簡化版&#xff1a;賬戶菜單按鈕&#xff08;AccountButton&#xff09; 我們以**“賬戶菜單按鈕”為例&#xff0c;用更清晰的架構實現一個支持標題顯示、漸變背景、選中狀態高亮**的自定義控件。以下是分步拆解&#xff1a; 一、控件核心功能 我們要做一個類似…

Deepseek+Xmind:秒速生成思維導圖與流程圖

deepseekxmind&#xff0c;快速生成思維導圖和流程圖 文章目錄 思維導圖deepseek筆記本 txt文件xmind 流程圖deepseekdraw.io 思維導圖 deepseek 筆記本 txt文件 將deep seek的東西復制到文本文件中&#xff0c;然后將txt文件拓展名改成md xmind 新建思維導圖----左上角三…

基于javaweb的SpringBoot愛游旅行平臺設計和實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論文…

服務器機架的功能和重要性

服務器已經成為各個行業必不可少的網絡設備&#xff0c;而服務器機架則是數據中心和IT基礎設施中不可或缺的重要組成部分&#xff0c;服務器機架能夠為服務器和其他網絡設備提供物理支撐&#xff0c;同時還可以提供設備維護和管理等多種功能&#xff0c;本文就來介紹一下服務器…

游戲引擎學習第277天:稀疏實體系統

回顧并為今天定下基調 上次我們結束的時候&#xff0c;基本上已經控制住了跳躍的部分&#xff0c;達到了我想要的效果&#xff0c;現在我們主要是在等待一些新的藝術資源。因此&#xff0c;等新藝術資源到位后&#xff0c;我們可能會重新處理跳躍的部分&#xff0c;因為現在的…

阿克曼-幻宇機器人系列教程1- 實現上位機與下位機交互的兩種方式

1. 電腦與機器人通過SSH命令連接 1.1 將機器人上電 目的&#xff1a;將機器人變成熱點 目標&#xff1a;將電腦連接機器人網絡 熱點名稱&#xff1a;Huanyu-111 密碼&#xff1a;12345678 1.2 完成電腦與機器人之間的連接 實現&#xff1a;在電腦終端中執行命令通過SSH登錄…

Rust 中的 Pin 和 Unpin:內存安全與異步編程的守護者

在 Rust 的世界里&#xff0c;Pin 和 Unpin 是兩個看似不起眼、實則至關重要的概念。它們在內存安全和異步編程中扮演著關鍵角色&#xff0c;是 Rust 開發者必須掌握的知識。今天&#xff0c;就讓我們深入探討這兩個概念&#xff0c;看看它們是如何在 Rust 的生態系統中發揮作用…

如何界定合法收集數據?

首席數據官高鵬律師團隊 在當今數字化時代&#xff0c;數據的價值日益凸顯&#xff0c;而合法收集數據成為了企業、機構以及各類組織必須嚴守的關鍵準則。作為律師&#xff0c;深入理解并準確界定合法收集數據的范疇&#xff0c;對于保障各方權益、維護法律秩序至關重要。 一…

自動駕駛的“眼睛”:用Python構建智能障礙物檢測系統

自動駕駛的“眼睛”:用Python構建智能障礙物檢測系統 在自動駕駛技術日益成熟的今天,障礙物檢測系統成了汽車智能化不可或缺的部分。無論是高速公路上的突發狀況,還是城市街道中的行人與車輛,準確識別障礙物并及時反應,是保證行車安全的關鍵。 那么,我們如何用Python構…

19.Excel數據透視表:第2部分數據透視計算

一 日期組合 不想看具體是哪一天的收入&#xff0c;想看每個月的收入是多少&#xff0c;要對日期進行組合。 光標選中日期字段下的數據&#xff0c; 右鍵。 補充&#xff1a;第2種方法。 補充&#xff1a;可以同時選擇多個。 下面這個是錯誤的。 源數據里面有不同的年份&#x…

Eclipse 插件開發 6 右鍵菜單

Eclipse 插件開發 6 右鍵菜單 1 plugin.xml2 SampleHandler.java3 Activator.java 1 plugin.xml <?xml version"1.0" encoding"UTF-8"?> <?eclipse version"3.4"?> <plugin><!-- 定義命令 --><extension point&…

用vite腳手架建立 前端工程

? 參考 開始 | Vite 官方中文文檔 腳本 chcp 65001 echo 建立vite工程 set PRO_NAMEmy-vue-app call npm create vitelatest %PRO_NAME% --template vue cd ./%PRO_NAME%set NOW_PATH%cd% echo now_path %NOW_PATH% echo 點擊回車啟動vite工程&#xff0c;請訪問ht…

ESP32C3連接wifi

文章目錄 &#x1f527; 一、ESP32-C3 連接 Wi-Fi 的基本原理&#xff08;STA 模式&#xff09;? 二、完整代碼 注釋講解&#xff08;適配 ESP32-C3&#xff09;&#x1f4cc; 三、幾個關鍵點解釋&#x1f51a; 四、小結 &#x1f527; 一、ESP32-C3 連接 Wi-Fi 的基本原理&a…

LangSmith 基本使用教程

LangSmith 是一個強大的工具&#xff0c;可以幫助開發者追蹤、監控和分析語言模型應用程序的性能。下面我將介紹兩種基本的追蹤方式&#xff1a;追蹤 OpenAI 調用和追蹤整個應用程序。 1. 追蹤 OpenAI 調用 (Trace OpenAI calls) 這種方法主要用于追蹤對 OpenAI API 的調用&a…

Python基礎學習-Day23

目錄 基礎概念轉換器&#xff08;transformer&#xff09;估計器&#xff08;estimator&#xff09;管道&#xff08;pipeline&#xff09; 實例pipeline 基礎概念 pipeline在機器學習領域可以翻譯為“管道”&#xff0c;也可以翻譯為“流水線”&#xff0c;是機器學習中一個重…

相對論速度疊加公式與雙曲正切

復習下相對論速度疊加公式吧&#xff0c;物理&#xff0c;是不是很多人都忘了呀。假設速度為 u , v u,v u,v&#xff0c;那么疊加后的速度 w w w為&#xff1a; w u v 1 u v / c 2 w\frac{uv}{1uv/c^2} w1uv/c2uv? ??這個公式告訴我們&#xff0c;在一個速度為2/3光速的…

【前綴和】和為 K 的子數組(medium)

【前綴和】和為 K 的子數組 題目描述算法原理和細節問題代碼 題目描述 和為 K 的子數組 給定一個整數數組和一個整數 k &#xff0c;請找到該數組中和為 k 的連續子數組的個數。 示例 1&#xff1a; 輸入:nums [1,1,1], k 2 輸出: 2 解釋: 此題 [1,1] 與 [1,1] 為兩種不同的…

在Ubuntu服務器上部署Label Studio

一、拉取鏡像 docker pull heartexlabs/label-studio:latest 二、啟動容器 &#xff08;回到用戶目錄&#xff0c;例&#xff1a;輸入pwd&#xff0c;顯示 /home/<user>&#xff09; docker run -d --name label-studio -it -p 8081:8080 -v $(pwd)/mydata:/label-st…