C++ 继承和派生 万字长文超详解

本文章内容来源于C++课堂上的听课笔记

继承和派生基础

继承是一种概念,它允许一个新创建的类(称为子类或派生类)获取另一个已经存在的类(称为父类或基类)的属性和行为。这就好比是子类继承了父类的特征。想象一下,如果有一个“动物”类,它有一些通用的特征和行为,然后我们有一个“猫”类,它可以继承“动物”类的这些通用特征,如四条腿、呼吸等。这样,“猫”类就继承了“动物”类

派生是指从已有类创建新类的过程。在这个过程中,新类继承了已有类的属性和方法。派生类可以添加新的属性或方法,也可以覆盖或修改继承的属性和方法。这就允许我们基于现有的代码构建和扩展新的功能。在上面的例子中,“猫”类就是通过派生(或继承)从“动物”类创建出来的

继承分为单继承和多重继承,如果一个派生类只有一个基类,就是单继承,否则是多重继承

派生类是基类的具体化,基类是派生类的抽象

假设已经声明了一个基类A,想要声明派生类B的一般形式为:

举个例子:

#include <iostream>
using namespace std;// 定义基类 Animal
class Animal {
public:void makeSound() {cout << "Some generic sound...\n";}
};// 定义派生类 Dog,它继承了 Animal 类
class Dog : public Animal {
public:void bark() {cout << "Woof! Woof!\n";}
};int main() {// 创建一个 Dog 对象Dog myDog;// 调用继承自 Animal 类的方法myDog.makeSound();// 调用派生类 Dog 自己的方法myDog.bark();return 0;
}

对于继承方式,一般有三种,分别是public,protected,private,如果不写继承方式,默认是private

派生类中的成员包括从基类继承的成员和新增的成员两大部分

构造派生类时,会涉及下面的一些事件:

1.从基类接收成员。派生类把基类全部的成员接收过来

2.调整从基类接收的成员。接收基类成员是程序人员不能选择的,但是程序人员可以对这些成员作某些调整。如:  通过指定继承方式,改变基类成员在派生类中的访问属性;  可以在派生类中声明一个与基类成员同名的成员,覆盖基类的同名成员(与重载是不同的,这里叫做重写override

3.在声明派生类时增加的成员

4.在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的

继承方式

上面说过,在声明派生类的时候要加一个名叫“继承方式”的东西,这里就对其进行相关的解释

公有继承

基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性; 而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员

#include <iostream>
using namespace std;// 定义基类 Vehicle
class Vehicle {
public:void startEngine() {cout << "Engine started.\n";}void stopEngine() {cout << "Engine stopped.\n";}
private:int m;
};// 定义派生类 ElectricCar,它公有继承自 Vehicle
class ElectricCar : public Vehicle {
public:void chargeBattery() {cout << "Battery is charging.\n";cout << m << endl;//无法访问}
};int main() {// 创建一个 ElectricCar 对象ElectricCar myElectricCar;// 使用继承自 Vehicle 类的方法myElectricCar.startEngine();// 使用 ElectricCar 类自己的方法myElectricCar.chargeBattery();// 使用继承自 Vehicle 类的方法myElectricCar.stopEngine();return 0;
}

私有继承

私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,在派生类外不能访问它们。 私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们

对于不需要再往下继承的类的功能可以用私有继承方式把它隐蔽起来,这样,下一层的派生类无法访问它的任何成员

#include <iostream>
#include <string>
using namespace std;// 定义基类 Person
class Person {
private:string name;int age;public:Person(const string& n, int a) : name(n), age(a) {}void displayInfo() {cout << "Name: " << name << ", Age: " << age << endl;}
};// 定义派生类 Employee,私有继承自 Person
class Employee : private Person {
private:string jobTitle;public:// 在 Employee 构造函数中初始化 Person 的成员Employee(const string& n, int a, const string& title): Person(n, a), jobTitle(title) {}void displayEmployeeInfo() {// 在 Employee 类的成员函数中,可以访问继承的 Person 成员displayInfo();cout << "Job Title: " << jobTitle << endl;}
};int main() {// 创建一个 Employee 对象Employee employee("John", 30, "Software Engineer");// 无法直接访问 Person 的私有成员// employee.displayInfo(); // 这行代码会导致编译错误// 但可以通过 Employee 的成员函数间接访问继承的 Person 成员employee.displayEmployeeInfo();return 0;
}

保护继承

保护成员:保护成员和私有成员类似,都不能直接被外界访问,但唯一不同的是保护成员可以被对应类的派生类的成员函数所访问

保护基类的公用成员和保护成员在派生类中都成了保护成员,其私有成员仍为基类私有。也就是把基类原有的公用成员也保护起来,不让类外任意访问

三种继承方式总结如下

派生类的构造函数和析构函数

上面说过子类不能继承父类的构造函数和析构函数,但有一种方法是可以让子类去调用父类的构造函数的,这样,就可以同时初始化父类成员和子类成员了

一般形式如下:

派生类构造函数名(总参数表列): 基类构造函数名(参数表列){派生类中新增数据成员初始化语句}

举一个例子:

Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s) //派生类构造函数
{    age=a;                        //在函数体中只对派生类新增的数据成员初始化addr=ad;
}

其中age,addr是派生类新增成员

也可以在类外实现派生类的构造函数,在类内仅仅声明即可

Student1∷Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)
{age=a;     addr=ad;}

在类中对派生类构造函数作声明时,不包括基类构造函数名及其参数表列

不仅可以利用初始化表对构造函数的数据成员初始化,而且可以利用初始化表调用派生类的基类构造函数,实现对基类数据成员的初始化。也可以在同一个构造函数的定义中同时实现这两种功能。

Student1(int n, string nam,char s,int a, string ad):Student(n,nam,s),age(a),addr(ad){}

在派生类对象释放时,先执行派生类析构函数~Student1( ),再执行其基类析构函数~Student( )

有子对象的构造函数和组合

什么是子对象?简单来说就是一个类的成员中包含一个类对象,这个类对象就是子对象(subobject),这个子对象也是可以直接在构造函数中一起初始化的,非常方便

注意,如果这个子对象是本派生类的基类,还是正常的继承

如果这个子对象是另外一个已定义的类称为类的组合

类的组合和继承一样,是软件重用的重要方式。组合和继承都是有效地利用已有类的资源。但二者的概念和用法不同。继承是纵向的,组合是横向的

#include <iostream>
#include <string>
using namespace std;// 定义基类 Student
class Student {
private:string name;int age;public:// 基类 Student 的构造函数Student(const string& n, int a) : name(n), age(a) {cout << "Student constructor called." << endl;}void displayInfo() {cout << "Name: " << name << ", Age: " << age << endl;}
};// 定义子对象 Grade
class Grade {
private:char grade;public:// Grade 构造函数Grade(char g) : grade(g) {cout << "Grade constructor called." << endl;}void displayGrade() {cout << "Grade: " << grade << endl;}
};// 定义派生类 Student1,包含一个子对象 Grade
class Student1 : public Student {
private:Grade studentGrade;public:// Student1 构造函数,调用基类 Student 和子对象 Grade 的构造函数Student1(const string& n, int a, char g): Student(n, a), studentGrade(g) {cout << "Student1 constructor called." << endl;}// Student1 类的成员函数,可以访问基类 Student 和子对象 Grade 的成员void displayStudent1Info() {displayInfo();        // 访问基类成员函数studentGrade.displayGrade();  // 访问子对象成员函数}
};int main() {// 创建一个 Student1 对象Student1 student1("Alice", 20, 'A');// 调用 Student1 类的成员函数,间接调用基类 Student 和子对象 Grade 的成员函数student1.displayStudent1Info();return 0;
}

执行派生类构造函数的顺序是: ① 调用基类构造函数,对基类数据成员初始化; ② 调用子对象构造函数,对子对象数据成员初始化; ③ 再执行派生类构造函数本身,对派生类数据成员初始化

基类构造函数和子对象的次序可以是任意的,如果有多个子对象,派生类构造函数的写法依此类推,应列出每一个子对象名及其参数表列。

多级派生时的构造函数

#include <iostream>
#include <string>using namespace std;// 基类 Person
class Person {
private:string name;public:// 基类构造函数Person(const string& n) : name(n) {cout << "Person constructor called." << endl;}void displayName() {cout << "Name: " << name << endl;}
};// 派生类 Student,继承自 Person
class Student : public Person {
private:int studentID;public:// Student 构造函数,调用基类 Person 构造函数Student(const string& n, int id) : Person(n), studentID(id) {cout << "Student constructor called." << endl;}void displayStudentInfo() {displayName(); // 访问基类成员函数cout << "Student ID: " << studentID << endl;}
};// 派生类 GraduateStudent,继承自 Student
class GraduateStudent : public Student {
private:string researchTopic;public:// GraduateStudent 构造函数,调用直接基类 Student 构造函数GraduateStudent(const string& n, int id, const string& topic): Student(n, id), researchTopic(topic) {cout << "GraduateStudent constructor called." << endl;}void displayGraduateStudentInfo() {displayStudentInfo(); // 访问直接基类 Student 的成员函数cout << "Research Topic: " << researchTopic << endl;}
};int main() {// 创建一个 GraduateStudent 对象GraduateStudent gradStudent("John Doe", 12345, "Machine Learning");// 调用 GraduateStudent 类的成员函数,间接调用基类 Person 和直接基类 Student 的成员函数gradStudent.displayGraduateStudentInfo();return 0;
}

main 函数中创建 GraduateStudent 对象时,首先调用 Person 类的构造函数,然后调用 Student 类的构造函数,最后调用 GraduateStudent 类的构造函数

派生类构造函数和析构函数注意点

1.当不需要对派生类新增的成员进行任何初始化操作时,派生类构造函数的函数体可以为空,即构造函数是空函数

2.如果在基类中没有定义构造函数,或定义了没有参数的构造函数,那么在定义派生类构造函数时可不写基类构造函数

3.如果在基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需对派生类自己的数据成员初始化,则可以不必显式地定义派生类构造函数

4.如果在基类或子对象类型的声明中定义了带参数的构造函数,那么就必须显式地定义派生类构造函数

5.如果在基类中既定义无参的构造函数,又定义了有参的构造函数(构造函数重载),则在定义派生类构造函数时,既可以包含基类构造函数及其参数,也可以不包含基类构造函数

6.在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子对象进行清理

7.调用的顺序与构造函数正好相反: 先执行派生类自己的析构函数,对派生类新增加的成员进行清理,然后调用子对象的析构函数,对子对象进行清理,最后调用基类的析构函数,对基类进行清理

多重继承

注意派生类中的构造函数怎么写的

#include <iostream>
#include <string>using namespace std;// 基类 Shape(形状)
class Shape {
protected:int width;int height;public:// Shape 类构造函数Shape(int w, int h) : width(w), height(h) {cout << "Shape constructor called." << endl;}void displayShapeInfo() {cout << "Shape - Width: " << width << ", Height: " << height << endl;}
};// 基类 Color(颜色)
class Color {
protected:string color;public:// Color 类构造函数Color(const string& c) : color(c) {cout << "Color constructor called." << endl;}void displayColor() {cout << "Color: " << color << endl;}
};// 派生类 ColoredShape(有颜色的形状),继承自 Shape 和 Color
class ColoredShape : public Shape, public Color {
public:// ColoredShape 类构造函数,显式调用基类构造函数ColoredShape(int w, int h, const string& c,int id) : Shape(w, h), Color(c) id(id){cout << "ColoredShape constructor called." << endl;}void displayColoredShapeInfo() {displayShapeInfo(); // 访问 Shape 类的成员函数displayColor();     // 访问 Color 类的成员函数}int id;
};int main() {// 创建一个 ColoredShape 对象ColoredShape coloredShape(10, 5, "Red");// 调用 ColoredShape 类的成员函数,间接调用基类 Shape 和 Color 的成员函数coloredShape.displayColoredShapeInfo();return 0;
}

虚基类

如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员

C++提供虚基类(virtual base class)的方法,使得在继承间接共同基类时只保留一份成员

虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。 声明虚基类的一般形式为

class 派生类名: virtual 继承方式 基类名

#include <iostream>// 基类:动物
class Animal {
public:Animal(const std::string& name) : name(name) {}void eat() const {std::cout << name << " is eating." << std::endl;}void sleep() const {std::cout << name << " is sleeping." << std::endl;}private:std::string name;
};// 虚基类:飞行动物
class FlyingAnimal : virtual public Animal {
public:FlyingAnimal(const std::string& name) : Animal(name) {}void fly() const {std::cout << Animal::getName() << " is flying." << std::endl;}
};// 派生类:哺乳动物
class Mammal : virtual public Animal {
public:Mammal(const std::string& name) : Animal(name) {}void giveBirth() const {std::cout << Animal::getName() << " is giving birth." << std::endl;}
};// 派生类:既是哺乳动物又可以飞的动物
class Bat : public FlyingAnimal, public Mammal {
public:Bat(const std::string& name) : Animal(name), FlyingAnimal(name), Mammal(name) {}
};int main() {Bat bat("Batman");// 通过虚基类,避免了二义性问题bat.eat();bat.sleep();bat.fly();bat.giveBirth();return 0;
}

基类和派生类的转换

在C++中,基类和派生类之间的转换主要涉及两种类型:向上转型(Upcasting)和向下转型(Downcasting)。这些转型可能涉及到指针和引用。

向上转型(Upcasting):

向上转型是将派生类的指针或引用转换为基类的指针或引用。这是一个安全的操作,因为派生类对象包含基类的部分。这样的转换通常是自动进行的,不需要显式的转换操作

#include <iostream>class Base {
public:virtual void display() const {std::cout << "Base class display" << std::endl;}
};class Derived : public Base {
public:void display() const override {std::cout << "Derived class display" << std::endl;}void additionalFunction() const {std::cout << "Additional function in the derived class" << std::endl;}
};int main() {Derived derivedObj;Base* basePtr = &derivedObj; // 向上转型// 调用的是 Derived 类的 display 方法basePtr->display();// 无法直接调用 Derived 类的 additionalFunction// basePtr->additionalFunction(); // 这行代码会产生编译错误return 0;
}

向下转型(Downcasting):

向下转型是将基类的指针或引用转换为派生类的指针或引用。这是一个潜在的危险操作,因为基类可能无法包含派生类的所有信息。因此,向下转型时通常需要进行显式的类型转换,并且应该在确保安全性的情况下进行

class Base {//...
};class Derived : public Base {//...
};int main() {Base* basePtr = new Derived();// 向下转型,需要显式的类型转换Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);if (derivedPtr) {// 转换成功,可以使用 derivedPtr 操作 Derived 类的成员} else {// 转换失败,basePtr 实际上不指向 Derived 类的对象}delete basePtr;return 0;
}

在上述代码中,使用了 dynamic_cast 运算符进行向下转型。这个运算符在运行时检查转型的有效性,如果转型合法,则返回指向派生类对象的指针;否则,返回空指针。

总的来说,向上转型是安全的,而向下转型需要谨慎并使用适当的手段进行检查,以避免潜在的运行时错误。在进行向下转型时,通常使用 dynamic_cast 运算符进行类型检查,或者在一些情况下,可以使用 static_cast 运算符,但要确保转型是安全的。

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

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

相关文章

【文末附资料链接】2023年第十三届亚太杯数学建模竞赛(APMCM)优秀参考论文思路指导(持续更新中ing)

一、赛事介绍 数学建模作为一门跨学科的科学&#xff0c;不仅需要对数学知识的熟练掌握&#xff0c;还需要对实际问题的深刻理解和解决问题的创新思维。亚太杯数学建模竞赛旨在激发青年学子的创造力和团队协作精神&#xff0c;培养其在实际问题中运用数学方法解决现实挑战的能力…

HarmonyOS ArkTS开发语言介绍(三)

1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xff0c;共同组成了相关的演进脉…

HarmonyOS脚手架:快捷实现ArkTs中json转对象

前言 在上篇《HarmonyOS开发&#xff1a;UI开展前的阶段总结》中提到了未来的规划&#xff0c;既能让大家学会鸿蒙开发&#xff0c;也能让大家在以后的开发中如虎添翼&#xff0c;最终决定&#xff0c;便以脚手架为产出物&#xff0c;结合实际的业务需求&#xff0c;进行相关技…

分享职业技术培训类型

职业技术培训类型包括&#xff1a;Python技术应用、人工智能应机器学习、大数据分析、机器学习。 一、“Python技术应用工程师” “Python技术应用工程师”职业技术认证是由工业和信息化部教育与考试中心推出一套专业化、科学化、系统化的人才考核标准&#xff0c;涉及在互…

【前端学java】Java中的异常处理(15)完结

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08;…

Windows系统搭建VisualSVN服务并结合内网穿透实现公网访问

目录 前言 1. VisualSVN安装与配置 2. VisualSVN Server管理界面配置 3. 安装cpolar内网穿透 3.1 注册账号 3.2 下载cpolar客户端 3.3 登录cpolar web ui管理界面 3.4 创建公网地址 4. 固定公网地址访问 总结 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源…

Chat GPT 用于论文润色,常用指令这里都全了

ChatGPT在多个方面对科研人员提供帮助&#xff0c;其中之一就是SCI论文润色&#xff0c;通过输入论文的摘要、引言或者段落&#xff0c;科研人员可获得ChatGPT生成的回复&#xff0c;包括修改建议、语法纠正、表达方式优化等。 指令润色 比如&#xff1a; 请帮我润色论文&am…

【【VDMA彩条显示实验之四 含C语言代码】】

VDMA彩条显示实验之四 含C语言代码 VTC 手册简介 所有的视频都需要有时序 有时序的地方就需要有 时序控制器 VTC的 主要作用是 产生 视频时序 相对于上一节 在这里 我们会理解的更多 观察 这个 HB 信号 其实这个和上一节的图片差不多 在 行同步信号 前面就是前沿 在 行同步…

基于SSM的高校毕业设计选题管理系统(有报告)。Javaee项目。

演示视频&#xff1a; 基于SSM的高校毕业设计选题管理系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring S…

可逆矩阵的性质

如果矩阵A可逆&#xff0c;那么它的逆矩阵也可逆&#xff0c;并且如果矩阵A可逆&#xff0c;假设是一个不为0的数&#xff0c;那么也可逆&#xff0c;并且如果矩阵A和都可逆&#xff0c;而且它们的阶数也相同&#xff0c;那么它们的乘积也是可逆的&#xff0c;并且如果矩阵A可逆…

详解SwinIR的论文和代码(SwinIR: Image Restoration Using Swin Transformer)

paper&#xff1a;https://arxiv.org/abs/2108.10257 code&#xff1a;https://github.com/JingyunLiang/SwinIR 目录 1. Swin Transformer layers1.1 局部注意力1.2 移动窗口机制1.3 关键代码理解 2. 整体网络结构2.1 浅层特征提取2.2 深层特征提取2.3 图像重建 3.总结 SwinI…

同城跑腿服务预约小程序的作用是什么

随着生活质量逐渐提升&#xff0c;围绕人们生活的行业或产品非常多&#xff0c;同时互联网赋能下&#xff0c;也出现了很多便捷人们日常消费的场景&#xff0c;如外卖服务、快递服务等。 跑腿仅依赖微信私聊及电话预约是很低效且容易出错及造成极大工作压力的&#xff0c;同时…

基于一致性算法的微电网分布式控制MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 本模型主要是基于一致性理论的自适应虚拟阻抗、二次电压补偿以及二次频率补偿&#xff0c;实现功率均分&#xff0c;保证电压以及频率稳定性。 一致性算法 分布式一致性控制主要分为两类&#xff1a;协调同…

Linux入门攻坚——6、磁盘管理——分区及文件系统管理

磁盘管理主要涉及分区的管理&#xff0c;以及分区后的文件系统管理。 磁盘的使用大体要分两步&#xff1a; 文件系统也是一个软件&#xff0c;根是自引用的。 文件系统的全局结构&#xff1a;物理格式&#xff1a; 一个磁盘刚被生产出来的时候&#xff0c;它里边没有划分扇区…

【Go入门】Web工作方式

【Go入门】 Web工作方式 我们平时浏览网页的时候,会打开浏览器&#xff0c;输入网址后按下回车键&#xff0c;然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后&#xff0c;到底隐藏了些什么呢&#xff1f; 对于普通的上网过程&#xff0c;系统其实是这样做的&…

基于RK3588的8k多屏异显安卓智能网络机顶盒

采用RK3588芯片方案的8K网络机顶盒&#xff0c;搭载纯净的安卓12操作系统&#xff0c;支持Ubuntu和Debian系统容拓展。主要面向外贸市场。此款机顶盒自带两个HDMI输出接口&#xff0c;一个HDMI输入接口&#xff0c;内置双频WiFi6无线模块&#xff0c;支持千兆以太网和USB接口。…

【文末送书】十大排序算法及C++代码实现

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

微创机器人:CRM撬动售后服务数字化升级

一方面&#xff0c;我国医疗器械行业起步较晚&#xff0c;更注重产品的销售和业务的拓展&#xff0c;企业售后服务整体比较滞后。 另一方面&#xff0c;医疗器械售后服务环节数字化程度不足&#xff0c;一些企业仍通过传统的线下手段管理售后服务&#xff0c;进行数字化尝试的…

【快速解决】实验四 对话框 《Android程序设计》实验报告

目录 前言 实验要求 实验四 对话框 正文开始 第一步建立项目 第二步选择empty views activity点击next ​编辑 第三步起名字&#xff0c;点击finish 第四步对 activity _main.xml文件操作进行布局 第五步&#xff0c;建立两个新文件&#xff0c;建立方法如下 SecondA…

SLAM中提到的相机位姿到底指什么?

不小心又绕进去了&#xff0c;所以掰一下。 以我个人最直观的理解&#xff0c;假设无旋转&#xff0c;相机在世界坐标系的(5,0,0)^T的位置上&#xff0c;所谓“位姿”&#xff0c;应该反映相机的位置&#xff0c;所以相机位姿应该如下&#xff1a; Eigen::Matrix4d T Eigen::M…