学习c++的第十一天

news2024/11/26 16:52:49

目录

继承和派生

基类 & 派生类

访问控制和继承

派生类的构造函数

派生类的析构函数

继承类型

多继承

重载运算符和重载函数

函数重载

运算符重载

可重载运算符/不可重载运算符

运算符重载实例


继承和派生

先来说继承,这与现实生活中的继承意思差不多,比如一个人继承另一个人的财产、以及子承父业等等是一个意思,拥有的这个过程就叫做继承。同样,在C++中,比如有两个类,新类拥有原有类的全部属性叫做继承!原有类产生新类的过程叫做派生!而我们把原有的这个类称之为父类基类,由基类派生出的类叫做派生类或者叫做子类。大家从名字上就可以看出他们的关系。

// 基类
class Animal {
    // eat() 函数
    // sleep() 函数
};


//派生类
class Dog : public Animal {
    // bark() 函数
};

 那么继承和派生有什么好处呢?为什么C++要有这种机制呢?

  1. 体现面向对象的编程思想,更好的表达各类型之间的关系。
  2. 派生类除了可以继承基类的全部信息外,还可以添加自己的那些不同的、有差异的信息,就像生物进化的道理一样,派生类在拥有基类的全部基础之上还将更强大。
  3. 派生类继承到基类的成员是自动、隐藏的拥有,即不需要我们重新定义,这就节省了大量的代码,体现了代码重用的软件工程思想。
  4. 继承和派生可以实现代码的模块化和分层,使得程序的结构更加清晰,易于理解和维护。通过继承和派生,我们可以将相似的代码抽象出来,形成一个基类,然后派生出不同的子类,分别实现各自的特定行为。

  5. 继承和派生可以实现多态性,使得程序的功能更加灵活和可扩展。通过基类的指针或引用,我们可以调用派生类的方法,从而实现对不同类型对象的统一操作。

  6. C++引入继承和派生机制,是为了继承C语言的优点,同时弥补其不足。C语言没有面向对象的概念,缺乏代码重用和抽象能力。通过继承和派生,C++可以更好地实现抽象、封装和多态等面向对象编程的特性。

基类 & 派生类

基类和派生类是面向对象编程中的两个重要概念。基类是指在继承关系中处于上层的、最通用的类,它定义了一组通用的属性和方法,派生类则是指在继承关系中处于下层、更具体的类,它从基类继承通用的属性和方法,并可以添加自己的特定属性和方法。

基类的概念源于面向对象编程的封装和抽象原则,其目的是将相似或相关的代码抽象出来,形成一个通用的类,避免代码冗余,提高代码的可维护性和可扩展性。基类通常包含一些数据成员和函数成员,而且这些成员的访问权限可以是public、protected或private。

派生类则是基于基类构建的,通过继承和派生机制,它可以从基类继承代码和数据,但也可以添加自己的特有信息。派生类可以覆盖或增加基类成员函数,重载基类成员函数,添加新的成员函数,以及定义新的数据成员等。派生类可以进一步派生出更加具体的子类,形成类似于树状结构的类层次体系。形式如下:

class derived-class: access-specifier base-class

其中,访问修饰符 access-specifier 是 public、protected 或 private 其中的一个,base-class 是之前定义过的某个类的名称。如果未使用访问修饰符 access-specifier,则默认为 private。 

在C++中,使用关键字class或struct定义一个类,它可以从一个或多个基类继承,例如:

class Animal {
public:
    void eat();
    void move();
protected:
    int age;
};

class Mammal : public Animal {
public:
    void giveBirth();
    void nurse();
private:
    int numOfPaws;
};

class Dog : public Mammal {
public:
    void bark();
private:
    string breed;
};

在上面的例子中,Animal是一个基类,它包含两个公共成员函数和一个保护的数据成员age。Mammal是一个派生类,它从Animal继承了eat()、move()和age成员,并添加了giveBirth()、nurse()和numOfPaws成员。Dog是Mammal的派生类,它除了继承Mammal的所有成员之外,还添加了一个私有成员breed和一个公共成员函数bark()。

基类和派生类的概念是面向对象编程中非常重要的基础,它们提供了代码重用、层次化组织、多态性等重要特性。

访问控制和继承

派生类可以访问基类中的所有非私有成员,这意味着基类成员如果不想被派生类的成员函数访问,应该将其声明为私有(private)。

根据访问权限,可以总结出以下不同的访问类型:

  1. 同一个类:在同一个类中,所有成员(无论是public、protected还是private)都是可以访问的。这意味着类中的任何成员函数都可以访问该类的所有成员。

  2. 派生类:派生类可以访问基类中所有的非私有(public和protected)成员,包括变量和函数。但是,对于基类中声明为私有(private)的成员,在派生类中是无法直接访问的。

  3. 外部的类:外部的类只能访问基类中声明为公共(public)的成员,对于受保护(protected)和私有(private)成员是无法访问的。这意味着,如果一个类想要访问另一个类的受保护和私有成员,那么它必须通过该类的公共成员函数来实现。

此外,在派生类继承基类时,派生类会继承基类的所有方法,但有几个例外情况:

  • 基类的构造函数、析构函数和拷贝构造函数:派生类需要定义自己的构造函数、析构函数和拷贝构造函数来处理自己的特定需求,而不是直接继承基类的相应函数。
  • 基类的重载运算符:派生类可以定义自己的重载运算符,但不会继承基类的重载运算符。
  • 基类的友元函数:派生类不能访问基类的友元函数,因为友元函数只对基类可见。

以下是一个示例: 

#include<iostream>

class BaseClass {
public:
    void publicMethod() { /* 实现代码 */ }
protected:
    void protectedMethod() { /* 实现代码 */ }
private:
    void privateMethod() { /* 实现代码 */ }
};

class DerivedClass : public BaseClass {
    // 可以访问继承的 public 和 protected 成员

public:
    void derivedMethod() {
        publicMethod();       // 可以访问继承的 public 成员
        protectedMethod();    // 可以访问继承的 protected 成员
        // privateMethod();   // 不能访问继承的 private 成员
    }
};

int main() {
    DerivedClass obj;
    obj.publicMethod();    // 可以通过对象访问继承的 public 成员
    // obj.protectedMethod(); // 不能通过对象访问继承的 protected 成员
    // obj.privateMethod();  // 不能通过对象访问继承的 private 成员

    return 0;
}

在上面的示例中,DerivedClass 是一个派生类,它继承了 BaseClass 的成员函数 publicMethod() 和 protectedMethod()。在派生类中,它们保持了原有的访问权限。派生类可以在自己的成员函数中使用继承的公共和受保护的成员函数。但是,私有成员函数 privateMethod() 对于派生类来说是不可见的。 

总的来说,通过继承,派生类可以访问基类中的成员,但对于私有成员、友元函数以及一些特殊情况(构造函数、析构函数、拷贝构造函数和重载运算符),存在一些限制。理解这些概念对于正确设计和使用继承关系是非常重要的。

派生类的构造函数

派生类的构造函数是在继承了基类的构造函数的基础上,对派生类自身进行初始化的一种特殊方法。派生类的构造函数可以调用基类的构造函数来初始化从基类继承而来的成员变量和方法。同时,派生类的构造函数也可以扩展或修改基类的构造函数。

派生类的构造函数的语法形式如下:

class Derived : public Base {
public:
    Derived(参数列表) : Base(参数列表) {
        // 派生类自身操作
    }
};

其中,Derived 是派生类的名称,Base 是基类的名称,参数列表 是传递给构造函数的参数,: Base(参数列表) 表示调用基类的构造函数进行初始化,// 派生类自身操作 则是派生类自己的初始化代码。

需要注意的是,如果派生类没有显式地调用基类的构造函数,则编译器会自动调用基类的默认构造函数进行初始化。如果基类没有默认构造函数,或者基类的构造函数不可访问(比如是私有构造函数),则派生类必须显式地调用基类的构造函数,否则会编译错误。

此外,在使用派生类的构造函数时,还需要遵循一些规则和约定,例如构造函数的名称与类名相同,构造函数不能有返回值等。

代码示例

#include <iostream>
using namespace std;

class Base {
public:
    Base(int a) { // 基类构造函数
        this->a = a;
        cout << "Base构造函数被调用" << endl;
    }
    void print() {
        cout << "Base::a = " << a << endl;
    }
private:
    int a;
};

class Derived : public Base {
public:
    Derived(int a, int b) : Base(a) { // 派生类构造函数
        this->b = b;
        cout << "Derived构造函数被调用" << endl;
    }
    void print() {
        Base::print(); // 调用基类的 print 方法
        cout << "Derived::b = " << b << endl;
    }
private:
    int b;
};

int main() {
    Derived d(1, 2);
    d.print();
    return 0;
}

在上面的代码中,Base 是基类,Derived 是派生类。Base 类有一个带有整型参数的构造函数,Derived 类继承了 Base 类,并添加了一个整型成员变量 b,同时还定义了一个带有两个整型参数的构造函数来初始化 b。

在 Derived 构造函数的初始化列表中,先调用了基类 Base 的构造函数来初始化从基类继承而来的成员变量 a,然后再将参数 b 赋值给派生类自身的成员变量 b。在构造函数中,输出一些调试信息,以便观察构造函数的执行情况。

在 Derived 类中,还重写了基类 Base 的 print 方法,在输出基类 Base 的成员变量 a 的值后,再输出派生类 Derived 的成员变量 b 的值。在 main 函数中,创建了一个 Derived 类型的对象 d 并调用了它的 print 方法。

当程序运行时,先输出 "Base构造函数被调用" 和 "Derived构造函数被调用",然后输出基类 Base 的成员变量 a 和派生类 Derived 的成员变量 b 的值。最终输出:

Base构造函数被调用
Derived构造函数被调用
Base::a = 1
Derived::b = 2

 总结:调用顺序是先调用基类的构造函数再调用派生类的构造函数

派生类的析构函数

派生类的析构函数是在派生类对象被销毁时调用的一种特殊成员函数。与构造函数相对应,在析构函数中可以进行清理操作,例如释放动态分配的内存、关闭文件等等。

派生类的析构函数与基类的析构函数的关系比较特殊。如果基类有虚析构函数,那么派生类的析构函数也应该是虚析构函数;如果基类没有虚析构函数,那么派生类的析构函数就不必是虚析构函数。这是因为,只有当我们使用基类的指针或引用来删除一个派生类对象时,才需要调用虚析构函数来确保正确地释放内存。

派生类的析构函数的语法形式如下:

class Derived : public Base {
public:
    ~Derived() {
        // 派生类自身的清理操作
    }
};

以下是一个派生类析构函数的代码示例,它与前面的派生类构造函数的示例非常类似:

#include <iostream>
using namespace std;

class Base {
public:
    Base(int a) { // 基类构造函数
        this->a = a;
        cout << "Base构造函数被调用" << endl;
    }
    virtual ~Base() { // 基类虚析构函数
        cout << "Base析构函数被调用" << endl;
    }
    void print() {
        cout << "Base::a = " << a << endl;
    }
private:
    int a;
};

class Derived : public Base {
public:
    Derived(int a, int b) : Base(a) { // 派生类构造函数
        this->b = b;
        cout << "Derived构造函数被调用" << endl;
    }
    ~Derived() { // 派生类析构函数
        cout << "Derived析构函数被调用" << endl;
    }
    void print() {
        Base::print(); // 调用基类的 print 方法
        cout << "Derived::b = " << b << endl;
    }
private:
    int b;
};

int main() {
    Base* p = new Derived(1, 2); // 使用基类指针来管理派生类对象
    p->print();
    delete p; // 删除派生类对象
    return 0;
}

在上面的代码中,Base 和 Derived 类的定义与前面的示例相同。不同之处在于,在 Base 类中添加了一个虚析构函数,在 Derived 类中添加了一个析构函数。在 main 函数中,使用基类指针 p 来管理一个 Derived 类型的对象,并调用它的 print 方法。最后,通过 delete 运算符删除 p 指向的对象,观察析构函数的执行情况。

当程序运行时,先输出 "Base构造函数被调用" 和 "Derived构造函数被调用",然后输出基类 Base 的成员变量 a 和派生类 Derived 的成员变量 b 的值。接着,当 delete p 执行时,先调用派生类 Derived 的析构函数,再调用基类 Base 的虚析构函数,输出 "Derived析构函数被调用" 和 "Base析构函数被调用"。最终输出:

Base构造函数被调用
Derived构造函数被调用
Base::a = 1
Derived析构函数被调用
Base析构函数被调用

总结:

在创建派生类对象时,首先会调用基类的构造函数,然后再调用派生类自身的构造函数。这是因为派生类继承了基类的成员变量和成员函数,需要先初始化基类的部分,然后才能执行派生类的构造过程。因此,在构造对象时,构造函数的调用顺序是从基类到派生类。

而在销毁派生类对象时,先调用派生类的析构函数,然后再调用基类的析构函数。这是因为派生类继承了基类的资源,需要先释放派生类自身的资源,然后再释放基类的资源。因此,在销毁对象时,析构函数的调用顺序是从派生类到基类。

继承类型

在C++中,有三种基本的继承类型:公共继承、保护继承和私有继承。它们决定了派生类如何继承基类的成员。

1、公共继承(public inheritance):
公共继承是最常用的继承方式。在公共继承中,基类中的公共成员和受保护成员都会成为派生类的公共成员和受保护成员。而基类中的私有成员仍然是基类自己的私有成员,无法被派生类访问。

公共继承的语法格式为:

class DerivedClass : public BaseClass
{
    //...
};

2、保护继承(protected inheritance):
在保护继承中,基类中的所有成员都将成为派生类的受保护成员。这意味着,基类中的公共成员将变为派生类的受保护成员,而基类中的私有成员仍然是基类自己的私有成员,无法被派生类访问。

保护继承的语法格式为:

class DerivedClass : protected BaseClass
{
    //...
};

3、私有继承(private inheritance):
在私有继承中,基类中的所有成员都将成为派生类的私有成员。这意味着,基类中的公共成员和受保护成员都将变为派生类的私有成员,而基类中的私有成员仍然是基类自己的私有成员,无法被派生类访问。

私有继承的语法格式为:

class DerivedClass : private BaseClass
{
    //...
};

需要注意的是,无论是公共继承、保护继承还是私有继承,都只影响到成员的访问权限,对于成员函数的重载、重写、隐藏等行为都没有影响。此外,派生类可以通过 using 关键字来改变从基类继承的成员的访问权限。

总的来说,继承类型决定了派生类如何继承基类的成员,理解它们的区别很重要,以便正确地设计和使用继承关系。在大多数情况下,公共继承是最常用的继承方式。

多继承

在面向对象编程中,一个类可以派生自多个基类,这被称为多重继承。通过使用类派生列表,我们可以指定派生类的多个基类。

类派生列表的语法如下:

class DerivedClass : access-specifier BaseClass1, access-specifier BaseClass2, ...
{
    // 类成员声明和定义
};

其中,access-specifier 是访问修饰符,可以是 public、protected 或 private,用于指定从每个基类继承的成员的访问权限。如果没有显式地指定访问修饰符,则默认为 private 访问权限。

通过多重继承,派生类可以从每个基类继承其成员函数和数据成员。需要注意的是,当多个基类拥有同名的成员函数或数据成员时,派生类必须通过作用域解析运算符明确指定要使用的成员。

下面是一个示例:

class BaseClass1 {
    // 基类1的成员和方法
};

class BaseClass2 {
    // 基类2的成员和方法
};

class DerivedClass : public BaseClass1, public BaseClass2 {
    // 派生类的成员和方法
};

在上述示例中,DerivedClass 是从 BaseClass1 和 BaseClass2 这两个基类中进行多继承的派生类。派生类将同时拥有这两个基类的成员和方法。

需要注意的是,在多继承中可能存在以下问题和注意事项:

1、名称冲突:如果多个基类具有相同的成员或方法名称,派生类在访问该成员或方法时需要进行限定,以避免歧义。

2、菱形继承问题:当多个基类之间存在继承关系时,派生类可能会继承相同的成员和方法多次,这被称为菱形继承问题。为了解决这个问题,可以使用虚继承(virtual inheritance)来避免重复继承。

class BaseClass {
    // 基类的成员和方法
};

class IntermediateClass1 : public virtual BaseClass {
    // 中间类1的成员和方法
};

class IntermediateClass2 : public virtual BaseClass {
    // 中间类2的成员和方法
};

class DerivedClass : public IntermediateClass1, public IntermediateClass2 {
    // 派生类的成员和方法
};

通过在基类之间使用 virtual 关键字,可以确保在派生类中只有一个实例共享基类的成员和方法。

多继承是一种强大的工具,但需要谨慎使用,特别是在存在名称冲突或复杂继承关系的情况下。

代码示例

#include<iostream>
using namespace std;

// 定义基类
class BaseClass {
public:
    // 基类的公有方法
    void baseFunc() {
        cout << "调用了基类的方法" << endl;
    }
};

// 定义中间类1,使用虚继承 BaseClass
class IntermediateClass1 : public virtual BaseClass {
public:
    // 中间类1的公有方法
    void intermediate1Func() {
        cout << "调用了中间类1的方法" << endl;
    }
};

// 定义中间类2,使用虚继承 BaseClass
class IntermediateClass2 : public virtual BaseClass {
public:
    // 中间类2的公有方法
    void intermediate2Func() {
        cout << "调用了中间类2的方法" << endl;
    }
};

// 定义派生类,从中间类1和中间类2进行多继承
class DerivedClass : public IntermediateClass1, public IntermediateClass2 {
public:
    // 派生类的公有方法
    void derivedFunc() {
        cout << "调用了派生类的方法" << endl;
    }
};

int main() {
    // 创建派生类对象
    DerivedClass obj;

    // 调用派生类的方法
    obj.derivedFunc();

    // 调用中间类1的方法
    obj.intermediate1Func();

    // 调用中间类2的方法
    obj.intermediate2Func();

    // 调用基类的方法
    obj.BaseClass::baseFunc();

    return 0;
}

在上述示例中,我们定义了一个基类 BaseClass,然后分别定义了两个中间类 IntermediateClass1 和 IntermediateClass2,它们都从基类 BaseClass 进行虚继承。最后,我们定义了派生类 DerivedClass,它从这两个中间类进行多重继承。

在 main 函数中,我们创建了 DerivedClass 的一个对象,并且分别调用了它自己的方法、以及从中间类和基类继承过来的方法。此外,我们还使用作用域限定符 :: 来标识调用基类 BaseClass 的方法。

编译并运行上述代码,可以得到如下输出:

调用了派生类的方法
调用了中间类1的方法
调用了中间类2的方法
调用了基类的方法

这表明虚继承和作用域限定符都起到了作用,确保派生类只继承了一份基类的成员和方法。

重载运算符和重载函数

C++ 允许在同一作用域中的某个函数运算符指定多个定义,分别称为函数重载运算符重载

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当调用一个重载函数重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

函数重载

函数重载是指在同一个作用域内,定义多个同名但参数列表不同的函数。通过函数重载,可以根据不同的参数类型和数量来调用相应的函数。

下面是一个使用函数重载的示例代码:

#include <iostream>
using namespace std;

// 函数重载示例
void print(int num) {
    cout << "整数: " << num << endl;
}

void print(double num) {
    cout << "浮点数: " << num << endl;
}

void print(char ch) {
    cout << "字符: " << ch << endl;
}

int main() {
    int a = 10;
    double b = 3.14;
    char c = 'A';

    // 调用不同参数类型的重载函数
    print(a);
    print(b);
    print(c);

    return 0;
}

在上述示例中,我们定义了三个重载的 print 函数,分别接受整数、浮点数和字符作为参数,并打印出对应的类型和值。

在 main 函数中,我们声明了一个整数变量 a、一个浮点数变量 b、一个字符变量 c,然后分别调用 print 函数来打印它们的值。由于参数类型不同,编译器会自动匹配调用相应类型的函数。

编译并运行上述代码,可以得到如下输出:

整数: 10
浮点数: 3.14
字符: A

这表明函数重载使得根据传入的参数类型和数量自动选择合适的函数成为可能。注意,函数重载的条件是参数列表不同,包括参数类型、参数个数或参数顺序。返回类型不同的函数不能构成重载。

运算符重载

运算符重载是指在类中重新定义和使用已有的运算符,使其适用于自定义类型的对象。通过运算符重载,可以方便地对对象执行各种操作,提高代码的可读性和易用性。

下面是一个使用运算符重载的示例代码:

#include <iostream>
using namespace std;

// 定义一个复数类
class Complex {
private:
    double real;
    double imaginary;

public:
    // 构造函数
    Complex(double r = 0.0, double i = 0.0) : real(r), imaginary(i) {}

    // 运算符重载:+
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imaginary + other.imaginary);
    }

    // 运算符重载:-
    Complex operator-(const Complex& other) const {
        return Complex(real - other.real, imaginary - other.imaginary);
    }

    // 运算符重载:*
    Complex operator*(const Complex& other) const {
        double r = real * other.real - imaginary * other.imaginary;
        double i = real * other.imaginary + imaginary * other.real;
        return Complex(r, i);
    }

    // 运算符重载:<<
    friend ostream& operator<<(ostream& os, const Complex& c) {
        os << "(" << c.real << ", " << c.imaginary << "i)";
        return os;
    }
};

int main() {
    Complex c1(2.0, 3.0);
    Complex c2(1.0, 4.0);

    // 使用重载的运算符进行操作
    Complex sum = c1 + c2;
    Complex diff = c1 - c2;
    Complex product = c1 * c2;

    // 输出结果
    cout << "c1 + c2 = " << sum << endl;
    cout << "c1 - c2 = " << diff << endl;
    cout << "c1 * c2 = " << product << endl;

    return 0;
}

在上述示例中,我们定义了一个复数类 Complex,其中包含实部和虚部。然后,我们通过运算符重载重新定义了 +、-、* 运算符,使其适用于 Complex 类型的对象。

此外,我们还通过友元函数重载了输出运算符 <<,以便能够通过 cout 打印复数对象。

在 main 函数中,我们创建了两个复数对象 c1 和 c2,并使用重载的运算符对它们进行操作,将结果存储到相应的变量中。最后,我们使用 cout 打印出运算结果。

编译并运行上述代码,可以得到如下输出:

c1 + c2 = (3, 7i)
c1 - c2 = (1, -1i)
c1 * c2 = (-10, 11i)

这表明通过运算符重载,我们可以像使用内置类型一样对自定义类型的对象执行各种操作。

可重载运算符/不可重载运算符

下面是可重载的运算符列表:

双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)
关系运算符==(等于),!= (不等于),< (小于),> (大于),<=(小于等于),>=(大于等于)
逻辑运算符||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++(自增),--(自减)
位运算符| (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)

下面是不可重载的运算符列表:

  • 成员访问运算符 .  用于访问类或结构体的成员。
  • 成员指针访问运算符 .* 和 ->* 用于访问类成员指针指向的成员。
  • 域运算符 :: 用于访问命名空间、类、结构体、枚举等的成员。
  • 长度运算符 sizeof 用于获取类型或表达式的字节大小。
  • 条件运算符 ?: 是三元运算符,用于根据条件选择两个表达式之一的值。
  • 预处理符号 # 用于预处理指令中的字符串化操作。

运算符重载实例

下面提供了各种运算符重载的实例,帮助您更好地理解重载的概念。

序号运算符和实例
1一元运算符重载
2二元运算符重载
3关系运算符重载
4输入/输出运算符重载
5++ 和 -- 运算符重载
6赋值运算符重载
7函数调用运算符 () 重载
8下标运算符 [] 重载
9类成员访问运算符 -> 重载

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

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

相关文章

2023年电工杯数学建模B题人工智能对大学生学习影响的评价求解全过程论文及程序

2023年电工杯数学建模 B题 人工智能对大学生学习影响的评价 原题再现&#xff1a; 人工智能简称AI&#xff0c;最初由麦卡锡、明斯基等科学家于1956年在美国达特茅斯学院开会研讨时提出。   2016年&#xff0c;人工智能AlphaGo 4:1战胜韩国围棋高手李世石&#xff0c;期后波…

【亚马逊云科技产品测评】活动征文|亚马逊云科技AWS之EC2详细测评

引言 &#xff08;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道&#xff09; 在当前的数字化时代&#xff0c;云服务已…

小饭店点餐系统,小餐馆点餐怎么方便,操作简单的酒店点单软件

小饭店点餐系统&#xff0c;小餐馆点餐怎么方便&#xff0c;操作简单的酒店点单软件 今天给大家分享是 佳易王酒店点餐管理系统软件V16.0版本&#xff0c;点餐界面如下图&#xff0c; 1、开台的桌子醒目显示&#xff0c;结账后或没有开台的桌子为灰色显示。 2、多种点餐方式…

Pytho入门教程之Python运行的三种方式

文章目录 一、交互式编程二、脚本式编程三、方式三关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 一、交互式编…

AMD老电脑超频及性能提升方案及实施

收拾电子元件的时候找到了若干古董的CPU 其中有一个X3 440 是原来同学主板烧了之后给我的&#xff0c;我从网上配了AM2 昂达主板&#xff0c;然后又买了AMD兼容内存&#xff0c;组成了win7 64位电脑&#xff0c;用起来非常不错&#xff0c;我把硬件配置和升级过程说明下&#x…

C++对象模型

思考&#xff1a;对于实现平面一个点的参数化。C的class封装看起来比C的struct更加的复杂&#xff0c;是否意味着产生更多的开销呢&#xff1f; 实际上并没有&#xff0c;类的封装不会产生额外的开销&#xff0c;其实&#xff0c;C中在布局以及存取上的额外开销是virtual引起的…

unittest 通过loadTestsFromName执行多个测试case

这段代码是一个使用unittest模块编写的测试运行程序。它的主要功能是加载其他Python文件中的测试用例并运行这些测试用例。 首先&#xff0c;定义了一个主测试类MainTestCase&#xff0c;该类继承自unittest.TestCase。在这个类中&#xff0c;可以添加各种测试方法来测试不同的…

产品经理入门学习(四):项目立项

参考引用 黑马-产品经理入门基础课程 1. 项目方案 1.1 主要阶段 立项阶段 基本方案&#xff1a;要做个什么项目&#xff0c;为什么要做这个项目&#xff0c;这个项目的作用和价值分别有哪些 上线阶段 设计阶段 运营阶段 开发阶段 总结阶段 测试阶段 2. 可行性分析 可…

Python语言_single_color_共140种--全平台可用

Python语言_single_color_共140种–全平台可用

3、Dockerfile 深入与其他细节

Dockerfile 在 Docker 中创建镜像最常用的方式&#xff0c;就是使用 Dockerfile。Dockerfile 是一个 Docker 镜像 的描述文件&#xff0c;我们可以理解成火箭发射的 A、B、C、D…的步骤。Dockerfile 其内部包含了一 条条的指令&#xff0c;每一条指令构建一层&#xff0c;因此每…

045_第三代软件开发-U盘监测

第三代软件开发-U盘监测 文章目录 第三代软件开发-U盘监测项目介绍U盘监测原理解释源代码 关键字&#xff1a; Qt、 Qml、 USB、 Disk、 文件 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#xff09;和…

1.如何实现统一的API前缀-web组件篇

文章目录 1. 问题的由来2.实现原理3. 总结 1. 问题的由来 系统提供了 2 种类型的用户&#xff0c;分别满足对应的管理后台、用户 App 场景。 两种场景的前缀不同&#xff0c;分别为/admin-api/和/app-api/&#xff0c;都写在一个controller里面&#xff0c;显然比较混乱。分开…

storm安装手册及笔记

图解Storm相关概念 图解storm的并发机制 安装Storm的步骤 1、安装一个zookeeper集群 2、上传storm的安装包&#xff0c;解压 3、修改配置文件storm.yaml #所使用的zookeeper集群主机 storm.zookeeper.servers: - "weekend05" - "weekend06"…

亚马逊 JDK下载地址

下载地址 https://docs.aws.amazon.com/corretto/选择版本 选择操作系统 比如 windows64 位 可以选择安装包或者解压版本 msi 的为安装版 zip 的为解压版

微积分第一章函数与极限

1.正反三角函数的导数 2.常用等价无穷小 3.正反三角函数转化&#xff1a; 1.secx1/cosx 2.cecx1/sinx 3.cotx1/tanx 4.基本数学思想&#xff1a; 1.有限式子与无限式子&#xff1a;在面对无限个式子运算时&#xff0c;大体思路为两个方面&#xff0c;第一个为放缩&#xff…

静态、友好、内在:解析C++中的这些特殊元素和对象复制的优化

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 前面我们学习了C中关于类与对象的许多知识点&#xff0c;今天我们继续学习类与对象&#xff0c;最后再总结一下类与对象中的一些关键字内容&#xff0c;以及需要注意的细节。满满的干货…

【H.264】RTP h264 码流 实例解析分析 3 : webrtc

【srs】SRS检测IBMF还是annexb 【H.264】RTP h264 码流 实例解析分析 2 : mediasoup收包 mediasoup 并没完整解析rtp包的内容,可能与mediasoup 只需要转发,不需要解码有关系。 webrtc 本身都是全的。 m98代码,先说关键: webrtc的VideoRtpDepacketizer 第一:对RTPVideoType…

年终述职技巧

一个共识 给个交代 复盘 给自己的交代 展示 给公司的交代 三维构思法 认知与成长 以己为师 萃取与迭代 以事为师 响应与前瞻 以人为师&#xff08;“作者视角”转变为“观众视角”&#xff0c;听懂、感兴趣、认可、有收获&#xff09; 六点通关术 论证价值点 工作成果&#x…

从《lc114. 二叉树展开为链表》到《lc-LCR 155二叉搜索树转化为排序的双向链表》

1 lc114. 二叉树展开为链表 1.1 描述 进阶&#xff1a;你可以使用原地算法&#xff08;O(1) 额外空间&#xff09;展开这棵树吗&#xff1f; 1.2 解法一&#xff1a; 先序遍历这棵树并且将节点加入到一个list中&#xff0c;随后按顺序将list中的每一个元素的left指针置换为…

AGV 导航方法总体设计与分析

导航方案设计 导航方法分为三个部分——路径规划、实时定位、轨迹纠正。 视觉定位模块 主要有三个工作任务&#xff1a;利用二维码定位对 AGV 初始位姿 进行矫正&#xff0c;保证 AGV 初始运动时其运动轨迹能够与道路平行&#xff1b;利用 ORBSLAM 定位能够实时的获得 AGV 在…