【C++】---多态

news2024/11/16 17:51:19

【C++】---多态

  • 一、多态的概念
  • 二、多态的定义及实现
    • 1、构成多态的2个必要条件
    • 2、什么叫做虚函数的重写?
    • 3、虚函数重写的3个例外
    • 4、建议把 析构函数 都定义为:虚函数
  • 三、C++11的两个关键字:final override
    • 1、final:修饰虚函数,表示该虚函数不能再被重写
    • 2、override: 检查是否重写
  • 四、重载、隐藏、重写 的比较
  • 五、多态的原理
    • 1、虚表(虚函数表)
    • 2、虚表指针:
    • 3、底层原理:满足多态后,在调用的指令中,指向谁 就去谁的虚表 里面 找对应的 虚函数 进行调用!
  • 六、抽象类
    • 1、纯虚函数
    • 2、抽象类(接口类)
    • 3、接口继承和实现继承
  • 七、单继承关系中的虚函数表
    • 1、单继承中的虚函数表
  • 八、继承和多态常见的面试问题
    • 1、选择题
    • 2、问答题

一、多态的概念

多态就是:多种形态。通俗的来说,多态的概念就是:同一件事情,不同的对象去做会有不同的结果。

二、多态的定义及实现

1、构成多态的2个必要条件

1. 子类必须对父类的虚函数进行重写(重写,包括三同:返回值相同,函数名相同,参数列表相同。协变除外)
2. 必须是父类的指针或者引用去调用虚函数,而且被调用的函数必须是虚函数。

2、什么叫做虚函数的重写?

1、什么叫做虚函数?

虚函数:在 成员函数 前面加 virtual

2、虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

#include<iostream>
using namespace std;

class Person
{
public:
	virtual void Buy_ticket()
	{
		cout << "成人-全价" << endl;
	}
};

class Student : public Person
{
public:
	virtual void Buy_ticket()
	{
		cout << "学生-半价" << endl;
	}
};

void Func(Person& p)
{
	p.Buy_ticket();
}

int main()
{
	Person p1;
	Student s1;

	Func(p1);
	Func(s1);

	return 0;
}

在这里插入图片描述

3、虚函数重写的3个例外

  1. 协变:基类 与 派生类 虚函数返回值类型 可以不同。派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。(了解)

协变 的代码

class A{};
class B : public A {};
class Person {
public:
 virtual A* f() {return new A;}
};
class Student : public Person {
public:
 virtual B* f() {return new B;}
};
  1. 子类的虚函数可以不写:virtual (因为形成多态后,如果存在调用子类的虚函数,实际上,只看子类虚函数的内部函数实现,不看头部,头部继承的父类,所以:子类虚函数可以不写:virtual)
    但是该种写法不是很规范,不建议这样使用

在这里插入图片描述

3、子类的虚函数中:析构函数,即使函数名不同,也会构成:重写!

解释:

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,

都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,

看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊
处理,编译后析构函数的名称统一处理成destructor!!!

class Person {
public:
 virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public:
 virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
 Person* p1 = new Person;
 Person* p2 = new Student;
 delete p1;
 delete p2;
 return 0;
}

4、建议把 析构函数 都定义为:虚函数

注意:如果不把析构函数都定义为虚函数的话,可能会发生内存泄漏!

1、自己好好想为什么建议把析构函数定义虚函数,防止发生内存泄漏?

因为如果所有的析构函数都定义为虚函数之后,它们所有的析构函数就会形成多态的关系,形成多态之后,就会达到我们的期望:delete的时候,子类对象调用子类的析构函数,父类对象要用父类的析构函数

如果在子类里面定义一个私有成员变量,如果所有析构函数不写成虚函数,无法满足多态的条件,没有形成多态的话,像上面子类有一个私成员变量,这个私有成员变量,无法被释放掉,就会导致内存泄漏。

在这里插入图片描述

三、C++11的两个关键字:final override

1、final:修饰虚函数,表示该虚函数不能再被重写

class Car
{
public:
 virtual void Drive() final {}
};
class Benz :public Car
{
public:
 virtual void Drive() {cout << "Benz-舒适" << endl;}
};

2、override: 检查是否重写

class Car{
public:
 virtual void Drive(){}
};
class Benz :public Car {
public:
 virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

四、重载、隐藏、重写 的比较

在这里插入图片描述

五、多态的原理

1、虚表(虚函数表)

// 这里常考一道笔试题:sizeof(Base)是多少?
class Base
{
public:
 virtual void Func1()
 {
 cout << "Func1()" << endl;
 }
private:
 int _b = 1;
};

在这里插入图片描述

// 针对上面的代码我们做出以下改造
// 1.我们增加一个派生类Derive去继承Base
// 2.Derive中重写Func1
// 3.Base再增加一个虚函数Func2和一个普通函数Func3
class Base
{
public:
 virtual void Func1()
 {
 cout << "Base::Func1()" << endl;
 }
 virtual void Func2()
 {
 cout << "Base::Func2()" << endl;
 }
 void Func3()
 {
 cout << "Base::Func3()" << endl;
 }
private:
 int _b = 1;
};
class Derive : public Base
{
public:
 virtual void Func1()
 {
cout << "Derive::Func1()" << endl;
 }
private:
 int _d = 2;
};
int main()
{
 Base b;
 Derive d;
 return 0;
}

在这里插入图片描述

  • 虚表:存在于哪里?常量区
  • 虚函数:和普通函数一样,存在代码段!
  • 虚函数指针:存在于:虚表

2、虚表指针:

虚表指针:
① 只要类里面有虚函数,就一定有虚表指针!
②同类型的对象,共用一张虚表

在这里插入图片描述

3、底层原理:满足多态后,在调用的指令中,指向谁 就去谁的虚表 里面 找对应的 虚函数 进行调用!

上面分析了这个半天了那么多态的原理到底是什么?还记得这里Func函数传Person调用的
Person::BuyTicket,传Student调用的是Student::BuyTicket

在这里插入图片描述
①满足多态后,在调用的指令中,指向谁 就去谁的虚表 里面 找对应的 虚函数 进行调用!
②如果函数不满足多态,那么就与指向的对象没有关系,跟你函数的形参类型有关系。
不满足多态,在编译链接时就直接,确定好调用函数的类型,地址!

在这里插入图片描述

六、抽象类

1、纯虚函数

定义:在虚函数的后面写上 =0

2、抽象类(接口类)

定义:包含纯虚函数的类

性质:抽象类不能实例化出对象。子类继承抽象类后也不能实例化出对象,只有重写纯虚函数,子类才能实例化出对象。

意义:

① 能够更好地去表示现实世界中没有实例对象是我抽象类型,如:植物、人、动物

② 体现接口继承,强制子类去重写虚函数(就算不重写,子类也是抽象类)

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();
}

抽象类不能实例化出对象:

int main()
{
	Animal a;
    return 0;
}

3、接口继承和实现继承

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

七、单继承关系中的虚函数表

1、单继承中的虚函数表

class Base { 
public :
 virtual void func1() { cout<<"Base::func1" <<endl;}
 virtual void func2() {cout<<"Base::func2" <<endl;}
private :
 int a;
};
class Derive :public Base { 
public :
 virtual void func1() {cout<<"Derive::func1" <<endl;}
 virtual void func3() {cout<<"Derive::func3" <<endl;}
 virtual void func4() {cout<<"Derive::func4" <<endl;}
private :
 int b;
};

在这里插入图片描述
在这里插入图片描述

八、继承和多态常见的面试问题

1、选择题

  1. 下面哪种面向对象的方法可以让你变得富有( )
    A: 继承 B: 封装 C: 多态 D: 抽象

答案: A 当然是继承更富有啦

  1. ( )是面向对象程序设计语言中的一种机制。这种机制实现了方法的定义与具体的对象无关,而对方法的调用则可以关联于具体的对象。
    A: 继承 B: 模板 C: 对象的自身引用 D: 动态绑定

答案: D 动态绑定是函数调用时关联到具体对象

  1. 面向对象设计中的继承和组合,下面说法错误的是?()
    A:继承允许我们覆盖重写父类的实现细节,父类的实现对于子类是可见的,是一种静态复用,也称为白盒复用
    B:组合的对象不需要关心各自的实现细节,之间的关系是在运行时候才确定的,是一种动态复用,也称为黑盒复用
    C:优先使用继承,而不是组合,是面向对象设计的第二原则
    D:继承可以使子类能自动继承父类的接口,但在设计模式中认为这是一种破坏了父类的封装性的表现

答案: C 尽量少用继承,会破坏封装原则,多用组合,能降低耦合度

  1. 以下关于纯虚函数的说法,正确的是( )
    A:声明纯虚函数的类不能实例化对象 B:声明纯虚函数的类是虚基类
    C:子类必须实现基类的纯虚函数 D:纯虚函数必须是空函数

答案: A 包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象

  1. 关于虚函数的描述正确的是( )
    A:派生类的虚函数与基类的虚函数具有不同的参数个数和类型 B:内联函数不能是虚函数
    C:派生类必须重新定义基类的虚函数 D:虚函数可以是一个static型的函数

答案: B inline函数没有地址,当inline成为虚函数后,虚表里面要放它的地址,构成多态时,根据虚函数表指针去call这个地址,就不能展开了,就忽略了内联属性,加了虚函数以后就不再是内联函数了。

  1. 关于虚表说法正确的是( )
    A:一个类只能有一张虚表
    B:基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表
    C:虚表是在运行期间动态生成的
    D:一个类的不同对象共享该类的虚表

对于A如果是多继承,那么这个类的对象会有多张虚表

对于B,监视:

#include<iostream>
using namespace std;
 
class Animal
{
public:
	virtual void Color()//颜色
	{
		cout << "virtual Animal::color" << endl;
	}
 
	virtual void Name()//名称
	{
		cout << "virtual Animal::name" << endl;
	}
};
 
class Coral :public Animal
{};
 
int main()
{
	Animal a;
	Coral c;
	
	return 0;
}

发现虚表指针不同,虽然虚表指针中存放的虚函数地址相同:

在这里插入图片描述
对于C:虚表在编译时就已经生成了

对于D:

#define  _CRT_SECURE_NO_WARNINGS  1
#include<iostream>
using namespace std;
 
class Animal
{
public:
	virtual void Color()//颜色
	{
		cout << "virtual Animal::color" << endl;
	}
 
	virtual void Name()//名称
	{
		cout << "virtual Animal::name" << endl;
	}
};
 
int main()
{
	Animal a;
	Animal a1;
 
	return 0;
}

监视发现:a和a1的虚表指针地址相同,虚表指针中存放的虚函数地址也相同

在这里插入图片描述

  1. 假设A类中有虚函数,B继承自A,B重写A中的虚函数,也没有定义任何虚函数,正确的是()
    A:A类对象的前4个字节存储虚表地址,B类对象前4个字节不是虚表地址
    B:A类对象和B类对象前4个字节存储的都是虚基表的地址
    C:A类对象和B类对象前4个字节存储的虚表地址相同
    D:A类和B类中的内容完全一样,但是A类和B类使用的不是同一张虚表

接下来是我对这一题的查缺补漏。一个选项一个选项,详细的解析一下

A、对于a选项来说,只要一个类里面有虚函数,这个类的内存里前4个字节都储存的是虚表的地址

B、 b选项和a选项是一样的。

C、关于这个虚表地址相同与否,可有的说了!

①:虽然现在有两个不同的类,但是如果子类没有对父类的虚函数进行重写行为,那么子类和父类 可能 共用一张虚表。
②:与①对立如果两个不同的类子类对父类的虚函数进行了重写行为,那么两者就用各自的去表。(因为这样就会构成多态,如果构成多态,调用谁,就去自己的虚表里面,找自己的虚函数地址)

答案:D 因为题目中已经说了子类对父类的虚函数进行了重写,所以说两者用的是各自的虚表。

  1. 下面程序输出结果是什么? ()
#include<iostream>

using namespace std;
class A{
public:
 A(char *s) { cout<<s<<endl; }
 ~A(){}
};
class B:virtual public A
{
public:
 B(char *s1,char*s2):A(s1) { cout<<s2<<endl; }
};
class C:virtual public A
{
public:
 C(char *s1,char*s2):A(s1) { cout<<s2<<endl; }
};
class D:public B,public C
{
public:
 D(char *s1,char *s2,char *s3,char *s4):B(s1,s2),C(s1,s3),A(s1)
 { cout<<s4<<endl;}
};
int main() {
 D *p=new D("class A","class B","class C","class D");
 delete p;
 return 0;
}

A:class A class B class C class D B:class D class B class C class A
C:class D class C class B class A D:class A class C class B class D

答案:A 子类构造函数必须调用父类的构造函数初始化父类的成员,因此执行D的构造函数前必须执行B和C的构造函数,执行B和C的构造函数前必须执行A的构造函数

  1. 多继承中指针偏移问题?下面说法正确的是( )
class Base1 {  public:  int _b1; };
class Base2 {  public:  int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main(){
 Derive d;
 Base1* p1 = &d;
 Base2* p2 = &d;
 Derive* p3 = &d;
 return 0;
}

A:p1 == p2 == p3 B:p1 < p2 < p3 C:p1 == p3 != p2 D:p1 != p2 != p3

在这里插入图片描述
10. 以下程序输出结果是什么()

class A
   {
   public:
       virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;}
virtual void test(){ func();}
   };
   
   class B : public A
   {
   public:
       void func(int val=0){ std::cout<<"B->"<< val <<std::endl; }
   };
   
   int main(int argc ,char* argv[])
   {
       B*p = new B;
       p->test();
       return 0;
   }

A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确

这里考察的一个点就是:虚函数重写,重写的是函数体实现,但函数结构部分(virtual 返回值 函数名 参数列表)用的还是父类的。
这就是为什么第3个例外:子类的虚函数可以不加virtual,因为他压根就不看子类前面的函数结构,他用是父类结构(virtual 返回值 函数名 参数列表)。

在这里插入图片描述

2、问答题

  1. 什么是多态?(不同的对象去完成同一件事情,产生了不同的结果)

  2. 多态的原理?(一句话:形成多态之后,指向谁,就去谁的虚表里面找对应的虚函数地址进行调用对应的虚函数。)
    当指针或引用指向父类对象时,调用的就是父类的虚表中的虚函数,当指针或引用指向子类对象时,调用的就是子类虚表中的虚函数。

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

答:不能,因为inline函数没有地址,无法把地址放到虚函数表中。

inline函数没有地址,当inline成为虚函数后,虚表里面要放它的地址,构成多态时,根据虚函数表指针去call这个地址,就不能展开了,就忽略了内联属性,加了虚函数以后就不再是内联函数了。

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

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

  1. 构造函数可以是虚函数吗?

答:不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。

假如构造函数是虚函数:

①调用构造函数虚函数必须要去虚表里面找,这就要求对象必须已经被初始化出来了。

②要初始化对象,就要调构造函数虚函数,但是对象还没有构造出来,虚表还没有初始化,还找不到构造函数虚函数地址。

这就陷入了死循环

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

答:可以,最好把基类的析构函数定义成虚函数。

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

答:

如果是普通对象,那么访问普通函数和虚函数是一样快的。

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

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

答:虚函数表是在编译阶段就生成的,一般情况下存在代码段(常量区)的。

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

答:子类对象会有两份父类的成员,菱形继承会导致数据冗余和二义性。

虚继承通过虚基表指针的偏移量计算出父类成员的起始地址,这样就只需要在内存中存一份父类成员,解决了数据冗余和二义性的问题。

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

答:包含纯虚函数的类叫做抽象类。

抽象类不能实例化出对象。子类继承抽象类后也是抽象类,没有重写虚函数,不能实例化出对象,只有重写纯虚函数,子类才能实例化出对象。

① 能够更好地去表示现实世界中没有实例对象是我抽象类型,如:植物、人、动物

② 体现接口继承,强制子类去重写虚函数(就算不重写,子类也是抽象类)


好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
在这里插入图片描述

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

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

相关文章

整理了10个靠谱且热门的赚钱软件,适合普通人长期做的赚钱副业

作为一名普通的上班族&#xff0c;我们每天都在辛勤工作&#xff0c;但工资的增长速度却如同蜗牛般缓慢。不过&#xff0c;别担心&#xff0c;信息时代总是带给我们无尽的惊喜&#xff01;今天&#xff0c;我将为大家推荐一些赚钱的宝藏软件&#xff0c;让你在闲暇之余轻松实现…

IPv4 报头 Protocol 字段和 IPv6 报头 Next header 字段中的 IP 协议号列表

IPv4 基本报头&#xff08;20 ~ 60 Byte&#xff09; IPv6 基本报头&#xff08;40 Byte&#xff09; IPv4 Header vs IPv6 Header 黄色 为 IPv6 与 IPv4 相同 红色 为 IPv6 删除的 蓝色 为名称不同功能相同 中青色 为新增的 Type of service Traffic Class &#xff08;用于…

Android ListView鼠标模式下ListView回滚问题

概述 在 Android 应用程序中&#xff0c;ListView 是一种常用的控件&#xff0c;用于显示可滚动列表数据。然而&#xff0c;当在鼠标操作模式下使用 ListView 时&#xff0c;可能会遇到一个问题&#xff1a;点击列表项时&#xff0c;列表会回滚到指定位置&#xff0c;这可能会导…

Windows、Linux下,基于QT的打包方法

整理这篇文档的意义在于&#xff1a;自己走了很多弯路&#xff0c;淋过雨所以想为别人撑伞&#xff0c;也方便回顾&#xff0c;仅供参考 ps: 第一次做Windows下打包&#xff0c;用了2小时&#xff0c;第二次20秒第一次做Linux(ubuntu)下打包&#xff0c;用了8小时&#xff0c;…

linux笔记6--shell相关

文章目录 1. 查看当前的shell类型2. ps -f命令3. 父子shell4. 分号在命令里的作用问题&#xff1a;环境变量echo&#xff1a; 5. sleep和jobssleep:jobs:例子&#xff1a;&: 6. 外部命令和内建命令图解外部命令type命令 7. history命令8. alias命令9. 推荐 1. 查看当前的sh…

C/C++ vector详解

要想了解STL&#xff0c;就必须会看&#xff1a; cplusplus.comhttps://legacy.cplusplus.com/ 官方内容全都是英文的&#xff0c;可以参考&#xff1a; C/C初始识https://blog.csdn.net/2301_77087344/article/details/138596294?spm1001.2014.3001.5501 vector&#xff…

01JAVA基础

目录 1.基础语法 1.1 注释 1.2 关键字 1.3 常量 1.4 数据类型 1.5 变量 1.6 标识符 1.7 类型转换 2.算数运算符和分支语句 2.1 算数运算符 1.常规运算符 2.赋值运算符 3.自增自减 4.关系运算符 5.逻辑运算符 6.三元运算符 2.2 数据输入(Scanner) 2.3 分支判断…

抖店如何打造出爆品?学好这几招,轻松打爆新品流量

大家好&#xff0c;我是电商花花。 近年来&#xff0c;抖店商家越来越多&#xff0c;而选品&#xff0c;爆品就是我们商家竞争的核心了&#xff0c;谁能选出好的新品&#xff0c;打造出爆品&#xff0c;谁的会赚的多&#xff0c;销量多。 做抖音小店想出单&#xff0c;想赚钱…

老外卖27刀每月的教程已经更新

用了两天半的时间&#xff0c;边学习&#xff0c;边整理了一份老外的视频教程&#xff0c;涉及Facebook&#xff0c;YouTube&#xff0c;tiktok等大的流量平台&#xff0c;有案例&#xff0c;有分析&#xff0c;有如何做。 这个教程是老外讲的&#xff0c;没有什么玄乎的塑造价…

UneMeta与日本顶级IP熊本熊合作,首个NFT玩法揭秘

UneMeta 生态是一个备受加密市场以及动漫 IP 市场关注的老牌 Web3 数字资产平台&#xff0c;旨在架起现实艺术 IP 和 NFT 艺术社区之间的桥梁&#xff0c;以促进 Web3 社区的包容性和多样性。并期望基于生态一流的产品体验和平台属性&#xff0c;打造一个包容交汇的元宇宙社区。…

美发店服务预约会员小程序的作用是什么

美发店不同于美容美甲&#xff0c;男女都是必需且年龄层几乎不限&#xff0c;商家在市场拓展时只要方法得当相对比较容易&#xff0c;当今客户适应于线上信息获取、咨询及实际内容开展&#xff0c;商家也需要赋能和提升自身服务效率&#xff0c;合理化管理。 运用【雨科】平台…

经济寒冬下的黄金跳板:方案、活动、竞标一手掌握

推荐策划人必备的宝藏地产策划资源平台&#xff0c; 订阅浩叫&#xff1a;地产营销策划圈。这个平台简直是地产策划人的百宝箱&#xff0c;里面藏着无数的策划秘籍&#xff0c;等着你来挖掘。 这个平台就像是一个大型的方案库&#xff0c;里面收录了众多知名地产企业的内部资料…

用three.js+echarts给公司写了一个站点数据大屏系统经验总结

时间过的好快,参加公司的新项目研发快一年了,五一机器人项目首秀,我们遇到了高并发集中下单情景,然后海量数据处理场景来了,给我在后端领域的高并发实践业务上画上了漂亮的一笔经验。人都是在磨练中成长,我很感谢这次给我的机会,虽然有点累,但也有点小成就。正好现在有…

docker 上面安装 Nginx 以及设置访问 IP 就可以访问前端工程

docker 运行 Nginx 第一步&#xff1a;搜索下镜像 首先可以使用 docker search nginx 搜索 nginx 服务 docker search nginx相关控制台输出&#xff1a; NAME DESCRIPTION STARS OFFICIAL…

电子商务网站(网上商店PetShop)

PetShop是一个范例&#xff0c;微软用它来展示.Net企业系统开发的能力。PetShop随着版本的不断更新&#xff0c;至现在基于.Net2.0的PetShop 4.0为止&#xff0c;整个设计逐渐变得成熟而优雅&#xff0c;有很多可以借鉴之处。PetShop是一个小型的项目&#xff0c;系统架构与代码…

统计信号处理基础 习题解答10-2

题目 两个随机变量x和y&#xff0c;如果联合PDF分解为&#xff1a; 那么称他们为条件独立的。在上式中z是条件随机变量。 我们观察 其中, , 是相互独立的。证明和是条件独立的。给出条件变量是A。和是无条件独立么&#xff1f;也就是 成立么&#xff1f;为了回答这个问题&…

flutter项目运行报错Exception: Gradle task assembleDebug failed with exit code 1各种报错合集

1.报错 Launching lib/main.dart on sdk gphone64 arm64 in debug mode... Running Gradle task assembleDebug... Exception in thread "main" java.net.ConnectException: Operation timed out at java.base/sun.nio.ch.Net.connect0(Native Method) at j…

【模版方法设计模式】

文章目录 模板方法设计模式模板方法的设计原则模板方法设计模式组成部分代码实现抽象类实现具体实现类执行 模板方法设计模式 模版方法设计模式&#xff08;Template Method Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个操作中的算法骨架&#xff0c;而将一…

欢乐钓鱼大师游戏攻略:自动钓鱼技巧!

《欢乐钓鱼大师》是一款极具趣味性和挑战性的钓鱼模拟游戏&#xff0c;为玩家提供了一个体验钓鱼乐趣的虚拟世界。从湖泊到河流&#xff0c;再到广袤的海洋&#xff0c;游戏中的各种钓场让人流连忘返。无论是新手钓友&#xff0c;还是经验丰富的老钓手&#xff0c;都可以在游戏…