【C++】继承与多态的常见问题解析

news2024/9/20 20:49:57

文章目录

  • 继承
    • 1.什么是菱形继承?菱形继承的问题是什么?
    • 2. 什么是菱形虚拟继承?如何解决数据冗余和二义性的
    • 3. 继承和组合的区别?什么时候用继承?什么时候用组合?
      • 1.继承(Inheritance):
      • 2. 组合(Composition):
  • 多态
    • 1. 什么是多态?
      • 1. 静态多态(静态多态绑定):
      • 2.动态多态(动态多态绑定):
    • 2. 什么是重载、重写(覆盖)、重定义(隐藏)?
    • 3. 多态的实现原理?
    • 4. `inline`函数可以是虚函数吗?
    • 5. 静态成员可以是虚函数吗?
    • 6. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?
    • 8. 对象访问普通函数快还是虚函数更快?
    • 9. 虚函数表是在什么阶段生成的,存在哪的?
    • 10. C++菱形继承的问题?虚继承的原理?
    • 11. 什么是抽象类?抽象类的作用?

在面向对象编程中,C++的继承和多态是非常重要的概念,它们为软件开发提供了灵活性、可扩展性和代码重用性。然而,在使用继承和多态时,也会遇到一些常见问题和需要注意的事项。本文将从菱形继承、多态、虚函数、抽象类等方面进行详细解析,希望能够帮助读者更好地理解和应用这些概念。

继承

1.什么是菱形继承?菱形继承的问题是什么?

菱形继承:菱形继承是多继承的一种特殊情况。
在这里插入图片描述
菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。
Assistant的对象中Person成员会有两份。

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; // 主修课程
};

void Test()
{
	// 这样会有二义性无法明确知道访问的是哪一个
	Assistant a;
	//  a._name = "peter";

	// 需要指明访问哪个父类成员可以解决二义性问题, 但是数据冗余问题无法解决
	a.Student::_name == "xxx";
	a.Teacher::_name == "xxx";
}

在这里插入图片描述

2. 什么是菱形虚拟继承?如何解决数据冗余和二义性的

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在StudentTeacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。

class Student : virtual public Person
{
	// ...
};
class Teacher : virtual public Person
{
	// ...
};


通过将 Person 声明为虚基类,可以确保在 Assistant 类中只有一份 Person类的数据成员,避免了数据冗余;同时,在访问 Person类的成员时,由于只有一份实例,消除了二义性问题。

3. 继承和组合的区别?什么时候用继承?什么时候用组合?

继承和组合是面向对象编程中两种不同的代码重用机制,它们有着各自的优势和适用场景。

1.继承(Inheritance):

  • 继承是一种“是什么”的关系,子类继承父类的属性和方法。
  • 适合用于表达"is-a"的关系,即子类是父类的一种特殊类型。
  • 可以通过继承实现代码复用和多态性。
  • 继承会导致子类与父类之间的耦合度增加,子类的实现依赖于父类的实现。
  • 适合用于共享通用行为和属性的情况。

2. 组合(Composition):

  • 组合是一种“有什么”的关系,一个类包含另一个类作为其成员变量。
  • 适合用于表示“has-a”关系,即一个类包含另一个类的实例作为其一部分。
  • 可以更灵活地构建对象的结构,减少耦合度。
  • 组合可以在运行时动态地改变对象的行为,提高了代码的灵活性和可维护性。
  • 适合用于构建对象之间的整体-部分关系。

在选择使用继承还是组合时,可以考虑以下几点:

  • 当新类是现有类的一种特殊类型,并且需要继承现有类的行为时,可以使用继承。
  • 当新类需要复用现有类的功能,但并非是现有类的特殊类型时,可以考虑使用组合。
  • 当希望通过改变对象的部分来改变对象的行为时,可以使用组合。
  • 当面临多层次的嵌套关系或者存在菱形继承等问题时,可以考虑使用组合来替代继承。

总的来说,继承适合用于表达"is-a"关系,组合适合用于表达"has-a"关系。在设计时根据具体情况选

在 C++ 中使用继承和组合:

#include <iostream>
using namespace std;

// 基类
class Shape {
public:
    void setWidth(int w) {
        width = w;
    }
    void setHeight(int h) {
        height = h;
    }

protected:
    int width;
    int height;
};

// 派生类,使用继承
class Rectangle : public Shape {
public:
    int getArea() {
        return (width * height);
    }
};

// 另一个派生类,使用组合
class Square {
private:
    Shape shape; // 包含一个 Shape 对象作为成员

public:
    void setSide(int s) {
        shape.setWidth(s);
        shape.setHeight(s);
    }

    int getArea() {
        return shape.getWidth() * shape.getHeight();
    }
};

int main() {
    Rectangle rect;
    rect.setWidth(5);
    rect.setHeight(7);
    cout << "Rectangle Area: " << rect.getArea() << endl;

    Square square;
    square.setSide(5);
    cout << "Square Area: " << square.getArea() << endl;

    return 0;
}

多态

1. 什么是多态?

在C++中,多态(polymorphism)是面向对象编程中一个重要的概念,它允许不同类的对象对同一消息做出响应。多态性可以分为静态多态(静态多态绑定)和动态多态(动态多态绑定)两种类型。

1. 静态多态(静态多态绑定):

静态多态是在编译时发生的多态,也称为早期绑定或编译时多态。静态多态通常通过函数重载和运算符重载实现。在静态多态中,编译器在编译时就决定了调用哪个函数或操作符。例如:

使用函数重载的示例:

#include <iostream>
using namespace std;

void print(int num) {
    cout << "Print integer: " << num << endl;
}

void print(double num) {
    cout << "Print double: " << num << endl;
}

int main() {
    int num1 = 10;
    double num2 = 3.14;

    print(num1); // 调用 print(int) 函数
    print(num2); // 调用 print(double) 函数

    return 0;
}

使用运算符重载的示例:

#include <iostream>
using namespace std;

class Vector {
private:
    int x;
    int y;

public:
    Vector(int x, int y) {
        this->x = x;
        this->y = y;
    }

    Vector operator+(const Vector& other) {
        int newX = this->x + other.x;
        int newY = this->y + other.y;
        return Vector(newX, newY);
    }

    void print() {
        cout << "Vector(" << x << ", " << y << ")" << endl;
    }
};

int main() {
    Vector v1(1, 2);
    Vector v2(3, 4);

    Vector v3 = v1 + v2; // 调用重载的 + 运算符

    v3.print();

    return 0;
}

2.动态多态(动态多态绑定):

动态多态是在运行时发生的多态,也称为晚期绑定或运行时多态。动态多态通过虚函数和纯虚函数实现。在动态多态中,函数的调用是在运行时确定的,根据指针或引用指向的实际对象类型来调用相应的函数。例如:

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() {
        cout << "Drawing shape..." << endl;
    }
};

class Circle : public Shape {
public:
    void draw() {
        cout << "Drawing circle..." << endl;
    }
};

int main() {
    Shape* s = new Shape();
    Shape* c = new Circle();

    s->draw(); // 调用 Shape 类中的 draw 函数
    c->draw(); // 调用 Circle 类中的 draw 函数

    delete s;
    delete c;

    return 0;
}

2. 什么是重载、重写(覆盖)、重定义(隐藏)?

重载(Overloading):指在同一个作用域内,函数名相同但参数列表不同的现象。通过函数重载,可以让同名函数根据参数的不同来执行不同的操作。编译器会根据函数的参数列表来区分不同的重载函数。重载不考虑函数的返回类型,只考虑函数的参数列表。

重写(Override):指子类重新定义(覆盖)了父类中的虚函数。在继承关系中,子类可以通过重写父类的虚函数来改变或扩展父类的行为。通过重写,子类可以在多态调用中动态地调用到自己定义的函数。

重定义(Hide):也称为隐藏,指子类定义了与父类同名的非虚函数。当子类中定义了一个与父类同名但参数列表不同的函数时,父类中的同名函数将被隐藏而不是被重写。这种情况下,在使用基类指针或引用调用该函数时,会调用基类中的函数,而不是子类中定义的函数。这种行为被称为函数的重定义或隐藏。

总结:

  • 重载是指在同一作用域内,函数名相同但参数列表不同;
  • 重写是指子类重新定义父类中的虚函数,实现多态性;
  • 重定义是指子类定义了与父类同名但参数列表不同的函数,导致父类函数被隐藏。

重写与隐藏的对比:

#include <iostream>

class Base {
public:
    virtual void print() {
        std::cout << "Base class print()" << std::endl;
    }

    void display() {
        std::cout << "Base class display()" << std::endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        std::cout << "Derived class print()" << std::endl;
    }

    void display(int num) {
        std::cout << "Derived class display(int)" << std::endl;
    }
};

int main() {
    Base* basePtr = new Derived;

    basePtr->print();    // 调用重写的虚函数
    basePtr->display();  // 调用基类中的非虚函数

    delete basePtr;

    return 0;
}

在上面的示例中,Base 类中有一个虚函数 print() 和一个非虚函数 display()Derived 类继承自 Base 类,并重写了 print() 函数,并在 Derived 类中定义了一个与 display() 参数列表不同的函数 display(int)

当我们通过基类指针 basePtr 调用函数时:

basePtr->print() 调用的是被重写的虚函数,会动态调用 Derived 类中的 print() 函数,输出 “Derived class print()”
basePtr->display() 调用的是基类中的非虚函数,因此输出 “Base class display()”
这就展示了重写和重定义(隐藏)在实际调用时的区别:重写会根据实际对象类型动态调用适当的函数,而重定义则会调用基类中的函数而不是派生类中定义的函数。

3. 多态的实现原理?

多态是面向对象编程中的一个重要概念,通过多态性可以实现不同对象对同一消息作出不同响应的能力。在C++中,多态性主要通过虚函数和指针/引用的动态绑定来实现。

具体来说,多态的实现原理如下:

  1. 虚函数(Virtual Function):在基类中使用 virtual 关键字声明的成员函数即为虚函数。派生类可以通过重写(Override)虚函数来改变或扩展基类的行为。
  2. 动态绑定(Dynamic Binding):当通过基类的指针或引用调用虚函数时,程序会根据指针或引用所指向的对象的实际类型来确定调用哪个版本的虚函数,这种机制称为动态绑定。
  3. 虚函数表(Virtual Table,VTable):编译器会为每个包含虚函数的类生成一个虚函数表,其中存储了各个虚函数的地址。每个对象都包含一个指向虚函数表的指针,当调用虚函数时,程序会根据该指针找到对应的虚函数并执行。
  4. 虚函数调用过程:当通过基类指针或引用调用虚函数时,程序会首先根据指针或引用的静态类型(基类类型)找到对应的虚函数表,然后根据表中的偏移量找到实际需要调用的函数,并执行。
  5. 实现多态性:通过虚函数和动态绑定的机制,不同类型的对象可以表现出不同的行为,从而实现了多态性,即同一类型的指针或引用在不同情况下表现出不同的行为。

总之,多态性通过虚函数和动态绑定机制实现,使得程序可以根据对象的实际类型来动态选择调用适当的函数,从而实现了灵活的对象行为表现。
指向父类,在父类的虚函数表中找到虚函数。指向子类会把子类中的切片切出来,然后在中间找找到的是覆盖重写后的虚函数。

在C++中,通过指向父类对象的指针或引用调用虚函数时,程序会在父类的虚函数表中找到对应的虚函数。而当指向子类对象的指针或引用调用虚函数时,会首先将子类对象切片(Slicing),然后在切片后的对象中找到被覆盖重写后的虚函数。

具体来说,当通过指向父类对象的指针或引用调用虚函数时,程序会在父类的虚函数表中找到对应的虚函数并执行;而通过指向子类对象的指针或引用调用虚函数时,会首先进行对象切片,即只保留子类对象中与父类相同部分的内容,然后在切片后的对象中找到被子类覆盖重写后的虚函数并执行。

这种动态绑定的机制使得程序能够根据对象的实际类型来调用适当的函数,实现了多态性,即同一类型的指针或引用在不同情况下表现出不同的行为。因此,在面向对象编程中,多态性是一种强大的特性,能够提高代码的灵活性和可扩展性。

4. inline函数可以是虚函数吗?

可以,不过编译器在多态调用的时候就忽略inline属性,这个函数就不再是inline,因为虚函数要放到虚表中去。而在普通调用的时候依然有inline属性。

5. 静态成员可以是虚函数吗?

,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。

6. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

析构函数可以被声明为虚函数。在C++中,将基类的析构函数声明为虚函数是一种良好的编程实践,特别是当使用指向派生类对象的基类指针时,通过将析构函数声明为虚函数可以确保在删除基类指针时正确调用派生类的析构函数,从而避免内存泄漏和未定义行为。

在以下场景下,将析构函数声明为虚函数是非常有必要的:

  1. 当基类指针指向派生类对象,并且在删除这个指针时需要调用派生类的析构函数时,应该将基类的析构函数声明为虚函数。
  2. 当使用多态性(Polymorphism)时,即通过基类指针或引用调用虚函数来实现动态绑定时,为了确保在销毁对象时调用正确的析构函数,应该将基类的析构函数声明为虚函数。
  3. 当基类中存在至少一个虚函数时,通常建议将析构函数也声明为虚函数,以避免潜在的问题。

总之,将析构函数声明为虚函数可以确保在多态情况下正确调用对象的析构函数,从而避免内存泄漏和其他问题。因此,在设计具有继承关系的类时,通常建议将析构函数声明为虚函数。

8. 对象访问普通函数快还是虚函数更快?

首先如果是普通对象(普通调用),是一样快的。如果是指针对象或者是引用对象(多态调用),则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。

9. 虚函数表是在什么阶段生成的,存在哪的?

虚函数表(vtable)是在编译阶段生成的,主要存在于程序的数据段(data segment)(常量区)中。在C++中,每个类(包括含有虚函数的类)都会在编译时生成一个虚函数表,用于存储该类的虚函数地址。当一个类包含虚函数时,编译器会为该类生成一个虚函数表,并在该类的对象中添加一个指向虚函数表的指针(通常称为虚函数指针)。

虚函数表中存储了该类的虚函数的地址,每个虚函数在虚函数表中占据一个固定的位置,通过虚函数指针可以根据偏移量找到对应的虚函数地址。当调用一个虚函数时,程序会通过虚函数指针找到对象所属类的虚函数表,并根据函数在虚函数表中的位置找到实际要调用的函数地址,从而实现动态绑定(Dynamic Binding)。

虚函数表的存在使得C++能够实现多态性(Polymorphism),即同一类型的指针或引用在不同情况下表现出不同的行为,提高了代码的灵活性和可维护性。虚函数表的生成是C++实现多态性的关键机制之一,也是面向对象编程的重要特征之一。

10. C++菱形继承的问题?虚继承的原理?

菱形虚拟继承(Diamond Inheritance)的原理涉及到虚基表(Virtual Base Table)。在菱形虚拟继承中,如果一个类同时从两个不同的路径继承同一个虚基类,那么为了避免出现两份相同的虚基类子对象,需要使用虚基类来解决这个问题。

在菱形虚拟继承中,每个派生类会包含一个指向虚基表的指针(通常称为虚基指针),这样可以在运行时准确定位虚基类的位置和偏移量。虚基表中存储了虚基类在派生类对象中的偏移量,以及虚基类的构造函数和析构函数的地址,通过虚基表,程序可以正确地访问共享的虚基类。

因此,虚基表是C++语言中用于实现菱形虚拟继承的关键机制,它能够确保在菱形继承情况下,共享的虚基类只会被构造一次,避免了资源浪费和访问冲突的问题。

11. 什么是抽象类?抽象类的作用?

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。

class Car
{
public:
	virtual void Drive() = 0;
};
class Benz :public Car
{
public:
	virtual void Drive()
	{
		cout << "Benz-舒适" << endl;
	}
};
class BMW :public Car
{
public:
	virtual void Drive()
	{
		cout << "BMW-操控" << endl;
	}
};
void Test()
{
	Car* pBenz = new Benz;
	pBenz->Drive();
	Car* pBMW = new BMW;
	pBMW->Drive();
}

接口继承和实现继承:普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

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

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

相关文章

数据迁移DTS | 云上MySQL 数据库迁移至达梦数据库

引入 云上 MySQL 数据库 —> 向达梦国产化数据库迁移 下载&安装 达梦客户端工具 DM->可参考之前国产化专栏达梦文章 创建模式 在客户端分别依次执行以下命令脚本&#xff08;这里没有通过客户端管理工具去创建达梦数据库的模式&#xff0c;当然也可以通过图形化界…

Find My运动相机|苹果Find My技术与相机结合,智能防丢,全球定位

运动相机设计用于在各种运动和极限环境中使用&#xff0c;如徒步、登山、攀岩、骑行、滑翔、滑雪、游泳和潜水等&#xff0c;它们通常具有防抖防震、深度防水和高清画质的特点&#xff0c;能够适应颠簸剧烈的环境&#xff0c;甚至可以承受一定程度的摔落&#xff0c;一些运动相…

自动化测试实例—Web登录功能性测试(无验证码)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是自动化测试 把人为驱动的测试行为转化为机器执行的一…

数据防泄漏的具体方法有哪些?数据防泄漏教程分享

曾经有一个非常严重的数据泄漏事件&#xff0c;是一家制造业相关的公司&#xff0c;经过调查&#xff0c;发现是员工在未经授权的情况下将客户数据通过电子邮件发送给了外部人员。 这一事件导致了客户隐私的泄露&#xff0c;给该机构带来了巨大的法律风险和声誉损失。 其实每…

DolphinScheduler——蔚来汽车数据治理开发平台的应用改造

目录 一、业务痛点 二、应用现状 三、技术改造 3.1 稳定性 3.1.1 滚动重启黑名单机制精准路由 3.2 易用性 依赖节点优化 补数任务优化 多 SQL 执行 原文大佬的这篇基于调度系统的数据治理案例有借鉴意义&#xff0c;这里摘抄下来用作学习和知识沉淀。 一、业务痛点 蔚…

tomcat 搭建博客 及破解数据库密码

一 tomcat 搭建博客 &#xff08;一&#xff09;博客安装包 1&#xff0c; 把博客war包 放到 webapps 文件夹下 2&#xff0c;会自动解压 3&#xff0c;做个软连接 方便后续操作 可以注意到 因为war包 是又tomcat 自己解压的 所以属主数组还是 tomcat &#xff08…

Redis性能攻略:Redis-benchmark工具与实用性能优化技巧

Redis作为一种高性能的内存数据库&#xff0c;广泛应用于各种业务场景。然而&#xff0c;随着业务规模的扩大和数据量的增长&#xff0c;Redis的性能问题逐渐凸显出来。为了提高Redis的性能&#xff0c;本文将深入探讨Redis性能优化方案&#xff0c;包括参数配置、数据结构、多…

Java的运行机制与Java开发环境的搭建

1.编译和执行 首先通过文本编辑器编写源程序&#xff08;后缀为.java&#xff09;&#xff0c;再利用编译器编译成字节码文件&#xff08;后缀为.class&#xff09;,最后利用虚拟机也叫解释器解释执行。 2.JVM、JRE和JDK的区别 简单来说&#xff0c; ①JVM 提供了运行 Java 程…

【HbuilderX】 uniapp实现 android申请权限 和 退出app返回桌面

目录 android申请权限&#xff1a; 监听用户是否开启权限或关闭权限&#xff1a; 退出app返回桌面&#xff1a; android申请权限&#xff1a; 首先在 manifest.json 内添加你所需要用到权限 添加权限插件 permission.js 一次就好1/权限插件 - Gitee.comhttps://gitee.co…

学习和工作的投入产出比(节选)

人工智能统领全文 推荐包含关于投入、产出、过剩、市场关注、案例、结果和避雷等主题的信息&#xff1a; 投入与产出&#xff1a; 投入和产出都有直接和间接两类常见形式。常见的四种组合是&#xff1a;直接投入、直接产出、间接投入、间接产出。 过剩&#xff1a; 过剩是一个重…

农产品质量追溯系统—简介

概要 农产品质量安全事关广大人民群众的食用安全和身体健康。解决农产品质量安全问题,需要从源头开始抓好、抓实农产品安全监管工作。通过建立从产地到市场的全程质量控制系统和追溯制度,对农产品产地环境、生产过程、产品检测、包装盒标识等关键环节进行监督管理,提高广大…

快速开发一个鸿蒙的页面

文章目录 前言常用组件快速开启简单的鸿蒙页面总结 一、前言 鸿蒙要想快速上手&#xff0c;那么就需要对基础的组件使用比较熟悉&#xff0c;这里就罗列开发中常见的基础组件的使用。 只要是写android的&#xff0c;对于这些组件的使用还是能很快上手的&#xff0c;只要多多…

AI智能分析网关V4智慧环保/智慧垃圾站视频智能分析与监控方案

一、背景介绍 随着城市化进程的加速&#xff0c;垃圾处理问题日益受到人们的关注&#xff0c;传统的垃圾站管理方式已经无法满足现代社会的需求。针对当前垃圾站的监管需求&#xff0c;TSINGSEE青犀可基于旗下视频智能检测AI智能分析网关V4与安防监控视频综合管理系统EasyCVR平…

【STM32】江科大STM32学习笔记汇总(50)

00. 目录 文章目录 00. 目录01. STM32学习笔记汇总02. 相关资料下载03. 附录 01. STM32学习笔记汇总 【STM32】STM32学习笔记-课程简介(01) 【STM32】STM32学习笔记-STM32简介(02) 【STM32】STM32学习笔记-软件安装(03) 【STM32】STM32学习笔记-新建工程(04) 【STM32】STM…

十年经验讲解功能测试的一些基本操作以及报告编写

一、 输入框测试 1. 字符型输入框&#xff1a; &#xff08;1&#xff09;字符型输入框&#xff1a;英文全半角、数字、空或者空格、特殊字符“~&#xff01;#&#xffe5;%……&*&#xff1f;[]{}”特别要注意单引号和&符号。禁止直接输入特殊字符时&#xff0c;使用…

[递归与递推] 栈与卡特兰数

题目背景 栈是计算机中经典的数据结构&#xff0c;简单的说&#xff0c;栈就是限制在一端进行插入删除操作的线性表。 栈有两种最重要的操作&#xff0c;即 pop&#xff08;从栈顶弹出一个元素&#xff09;和 push&#xff08;将一个元素进栈&#xff09;。 栈的重要性不言自…

每日一“类“:深入理解Qt的心脏《QObject》

Qt框架以其强大的跨平台能力和丰富的用户界面元素而广受开发者欢迎&#xff0c;而QObject类无疑是Qt框架心脏的所在。本文将深入探讨QObject&#xff0c;揭示其提供的核心功能以及如何在Qt项目中有效利用这个基类。 核心功能 信号与槽 Qt独特的信号与槽机制是其事件通信的基…

【Rust】——结构体struct

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

vue系列——vscode,node.js vue开发环境搭建

第一步安装node.js 推荐使用nvm进行node.js 的安装 nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 可以去网上查找相关版本 我这里使用 nvm-setu… 链接:https://pan.baidu.com/s/1UEUtmzw5x…

spring事务方法调用不生效的场景

同一个类中&#xff0c;事务方法调用非事务方法时&#xff0c;事务是可以生效的。反例事务不生效见以下 4. 同一个类中&#xff0c;方法内部调用 Autowired private XXXMapper xxxMapper; Autowired private YYYMapper yyyMapper; Transactional public ResultVO<AssetCh…