C++进阶—>这3个问题难道搞不懂多态???

在这里插入图片描述

文章目录

  • 🚩前言
    • 1、它是什么?
    • 2、怎样实现它??
      • 2.1、虚函数是个什么来头?✍
      • 2.2、虚函数的重写/覆盖特殊点!👀
      • 2.3、在了解多态的必要条件以及虚函数后,来看下如何编写吧👀👀
      • 2.4、经典面试题
    • 3、虚函数的其余问题解析✍
      • 3.1、协变?
      • 3.2、纯虚函数和抽象类?🔊
      • 3.3、析构函数的重写
      • 3.4、override和final关键字?
    • 4、它为什么是这样的结果(底层原理)???
      • 4.1、初识虚函数表?
      • 4.2、初看虚函数表指针?
      • 4.3、多态实现的原理?
      • 4.4、动态绑定和静态绑定
      • 4.5、再探虚函数表

🚩前言

该模块属于C++进阶内容,通过三个问题(是什么?——>怎么实现??——>为什么可以这样???)来理解多态这个陌生的词语,以及底层原理?

1、它是什么?

“多态”——>字面意思理解,即多种形态。
既然是多种形态,那么C++多态有哪几种呢?
主要分为编译时多态[静态多态]和运行时多态[动态多态]
编译时多态——》主要体现在函数重载和函数模版。通过传入不同类型的参数就可以调用不同的函数,通过传入参数来实现多种形态。该过程叫编译时多态,是因为实参传给形参的进行参数匹配时候,是在编译的时候完成的。
运行时多态——》主要体现在继承体系过程的,通过传入不同对象,来完成对应对象的函数(方法)。这里有两个例子来描述:

①车站买票的时候:成年人、学生、儿童以及军人在C++中可以理解为不同的对象,在买票的时候,从生活中买票都可以知道,不同对象买票是有不同价格的。然而达到不同价格买票,就是实现不同的方法。

②动物发出叫声:我们知道不同动物发出的叫声是不一样的,狗狗🐶是"汪汪……",
猫猫🐱是发出“喵喵……”等不同的动物,这些都是多个对象,但它们同属于动物系,由于对象不同,因此发出声音这一方法(函数)就会不同。

这两个就是多态的例子,下面会讲怎样实现多态。

2、怎样实现它??

多态的构成条件,即前提是在继承关系之下的类和对象,不同对象调用同一函数实现不同方法(行为)。
在实现它之前必须得知道到达多态的必要条件,有两个:
①必须基类(父类)的指针或引用来调用虚函数。
②被调用的函数必须是虚函数。

注意事项:①必须是基类的指针或引用,因为只有基类的指针或引用才能指向派生类的对象。②派生类必须对基类的虚函数进行重写/覆盖,只有这样派生类才能实现自己的方法,进一步达到多态的效果。

那么虚函数???是什么呢?因此在实现多态之前有必要讲解虚函数是什么?

2.1、虚函数是个什么来头?✍

“虚函数”:它的实现很简单,就是在函数前面加关键字virtual,就成该函数为虚函数。
值得注意的是非成员函数不能加vitrual关键修饰。
【原因在于非成员函数(非类成员函数)只能被overload,而不能被override。虚函数的主要目的是支持类多态,允许子类继承并覆盖父类中的虚函数,实现动态绑定。由于非成员函数不具备这种继承和覆盖的特性,因此将其定义为虚函数没有实际意义,编译器也无法处理这种定义,从而导致无法通过编译。此外,虚函数是在运行时动态绑定的,而非成员函数在编译时就已经确定,这与虚函数的动态绑定机制相冲突,因此非成员函数不能加virtual修饰‌。】

2.2、虚函数的重写/覆盖特殊点!👀

  1. 虚函数的重写/覆盖:也就是在派生类中有跟基类完全相同的虚函数,就达成虚函数的重写/覆盖,达成条件就是要“3同”,即①函数名相同。②函数的返回值类型相同。③参数列表类型相同。就完成派生类的虚函数重写了父类的虚函数。
  2. ==注意:==在重写基类虚函数的时候,派生类的虚函数可以省略关键字“virtual”【在继承之前基类的函数已经有了虚函数的属性,继承后依然保持虚函数属性】,但是为了规范,建议写上。只是在考试或者面试中需要注意埋的这个“坑”。

2.3、在了解多态的必要条件以及虚函数后,来看下如何编写吧👀👀

例1

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>//多态例子1——>买票
//不管哪一个对象买票,都是属于Person这个父类的,因此先创建一个父类
class Person
{
public://默认是成年人买票,都是全价票,基类函数必须写为虚函数virtual void Tickets(){std::cout << "成年人——>全价票:" << std::endl;}
};//然后是其他对象买票,
//学生对象
class Student :public Person
{
public://重写虚函数,可省略关键字,为规范建议加上。virtual void Tickets(){std::cout << "学生——>半价优惠:" << std::endl;}
};//买票
void BuyTickets(Person& per)//必须是基类的指针或者引用
{per.Tickets();//指针也可以。//per->Tickets();
}int main()
{Person per1;Student stu1;BuyTickets(per1);BuyTickets(stu1);//也可以写为下面那种。//Person* per1 = new Person;//Person* stu1 = new Student;//per1->Tickets();//stu1->Tickets();return 0;
}

在这里插入图片描述

例2

#include<iostream>
//多态例子2——>动物叫
//基类——>Animal
class Animal
{
public://创建虚函数virtual void talk() const{}
};class Dog :public Animal
{
public://重写基类虚函数virtual void talk() const{std::cout << "狗狗叫——>汪汪……" << std::endl;}
};class Cat :public Animal
{
public: //重写virtual void talk() const{std::cout << "猫猫叫——>喵喵……" << std::endl;}
};void Animal_talk(const Animal& animal)
{//animal->talk();//基类指针调用,也可以引用//写引用,参数记得跟着变animal.talk();
}int main()
{Dog dog1;Cat cat1;Animal_talk(dog1);Animal_talk(cat1);return 0;
}

在这里插入图片描述

2.4、经典面试题

以下程序输出结果是什么()
A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确

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

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

3、虚函数的其余问题解析✍

在这里说一说协变、纯虚函数和抽象类。

3.1、协变?

这里说协变,是和多态中“3同”有些冲突的,但是这是特殊情况,作为了解即可。
主要是在派生类重写基类虚函数的时候,出现派生返回类型和基类的类型不一样,即基类返回基类的指针/引用,而派生类返回自己的指针/应用,就称为协变。一般没怎么用,只要提到“协变”这个词后,不陌生就ok了。👌

3.2、纯虚函数和抽象类?🔊

纯虚函数定义:就是在虚函数后面加“=0”即可。
class Car
{
public:
  virtual void Drive() = 0;
};
纯虚函数不需要定义实现,只写声明即可。因为定义实现后一样会被派生类重写,所以意义不大,从语法上是可以实现的。
那么包含纯虚函数的类叫作抽象类。
抽象类是不能实例化出对象的,若派生类继承抽象类后,不重写纯虚函数的话,派生类也是抽象类。
可以说纯虚函数在某种程度上强制了派生类必须重写虚函数,不重写无法实例化出对象,就无意义了。

3.3、析构函数的重写

析构函数的重写有这样一个规定:
当基类的析构函数为虚函数的时候,派生类只要定义析构函数后,无论加还是不加virtual,都和基类的析构函数构成重写。有人会说基类的析构函数名和派生类的析构函数名完全不同,怎么构成重写的呢?这就是编译器的作用,实际上编译器对析构函数名做了特殊处理,就是编译后析构函数名称会被统一处理成destructor,所以基类的析构函数写为虚函数后,和派生类定义的析构函数是构成重写的。

注意:在多态条件下,只要基类定义了析构函数,就必须加关键字virtual,不然会出问题,以下面例子为参考👇👇👇👇

为什么基类的中的析构函数建议设计为虚函数呢?
有此类情况:一个基类和一个派生类,两个构成继承关系,那么程序结束后,怎么释放?得调用析构函数,由于在多态中显示写析构函数后,派生类的析构函数和基类的析构函数是构成重写的。main()函数中创建两个对象,基类的对象是基类的指针,派生类的对象也是基类的指针,只是指向的对象不同,因此在析构时候,基类释放基类空间是没问题的,而由于是继承关系,若基类析构函数不加virtual关键字就不构成多态,那么派生类在调用析构时候就会出问题,因为创建的对象都是基类指针类型,调用函数就是指向谁调用谁的函数,在这里就得调用析构函数,但是基类的析构函数没加virtual,就不构成多态,那么派生类在调用析构时候就无法调用到自己重写的析构函数,就会造成无法释放造成内存泄漏。下面是代码实现演示:👇

构成继承,但不构成多态,释放会出问题

#include<iostream>
class A
{
public://基类析构不是虚函数~A(){std::cout << "析构:~A()" << std::endl;}
};class B :public A
{
public:virtual ~B(){std::cout << "析构:~B()"<< std::endl;}
};int main()
{//两个对象类型都是基类的指针,差别就是指向对象不一样A* a = new A;A* b = new B;//在结束后需要析构,由于是指针需要显示写deletedelete a;delete b;return 0;
}

在这里插入图片描述

下面程序构成继承和多态,释放正常

代码编写就是在上面代码中的基类析构函前面加关键字virtual,即可。
运行显示结果在下面,释放正常,这里可能会有疑问,为什么a对象析构两次呢?第一个~A()是创建的对象调用的, ~B()是对象b调用的,那么最后一个 ~A()呢?在继承关系中,派生类是合成版本,就是说里面含有父类的一部分,在析构的时候,子类调用自己的析构,父类那一部分就调用父类的析构。因此后面又析构一次。
在这里插入图片描述
总结:为什么基类析构要加virtual?
如果基类析构不加virtual,那么在析构派生类的空间的时候就只会调用基类,析构基类那一部分空间,派生类的就会无法释放就出现内存泄漏。

3.4、override和final关键字?

override 关键字是:帮助用户检查之后构成重写。
因为在C++中对虚函数构成重写很严格,在不经意中用户书写时可能会出现错误,比如函数名、参数写错等,导致无法构成重写,改错误在编译期间无法检查出,因此该关键字就起到提示作用。

final 关键字是:就是不想让派生类重写基类的这个虚函数的时候,就可以用final修饰。

4、它为什么是这样的结果(底层原理)???

在知道多态是怎样实现的,就需要知道虚函数表、虚函数表这两个词语!

4.1、初识虚函数表?

先从虚函数表是用来干什么的说起,首先虚函数表,可以简称“虚表”,是用来存储虚函数地址的。
哪里的虚函数呢?就是类中带有virtual关键字的函数的地址。
既然它是存放地址的,并且可以存放多个地址,因此虚函数表的本质就是存放虚函数指针(地址)的指针数组,在数组末尾会以0x00000000标记结尾的(在vs中会,而g++中没有)。

4.2、初看虚函数表指针?

虚函数表指针?看名字可以知道是一个地址,谁的地址?即虚函数表的地址。下面通过一个实例程序来分析:

#include<iostream>
class Base
{
public:virtual void Func1(){std::cout << "Func1()" << std::endl;}
protected:int _b = 1;char _ch = 'x';
};int main()
{Base b;std::cout << sizeof(b) << std::endl;return 0;
}

在这里插入图片描述
从运行结果看怎么会是12呢?根据自己的分析,成员有两个,结合图来看
在这里插入图片描述
在这里插入图片描述
这样算下来是8Byte,为什么运行时结果为12Byte?

接下来看下面的调试图片,会看到不一样的东西👀👀
在这里插入图片描述
相信可以看到蓝色那一栏吧!_vfptr是什么空间呢?它就是虚函数表指针,简称虚表指针,后面0x00499b34就是虚函数表的地址,_vfptr就是虚函数表指针名。因为是指针,又是在32位下,指针要占4字节,因此总空间就变化为下图的:
在这里插入图片描述

相信到达这里搞清楚了为什么运行出来是12Byte,,接下来看一下,上面说过虚函数表是存储虚函数地址的,并且虚函数表也有自己的地址,叫虚函数表指针,因此整个逻辑就是有一个虚函数表,虚函数表指针指向的是虚函数表,在虚函数表中存放着虚函数的地址,下图可见:
在这里插入图片描述

4.3、多态实现的原理?

在弄清楚虚函数表和虚函数表指针以及了解了虚函数地址存放位置后,现在看一下怎么实现调用的,下来实现一个完整的多态:

#include<iostream>class Person
{
public://实现多态记得基类要有虚函数virtual void BuyTicket(){std::cout << "Person->全价票" << std::endl;}
private:int age;char gender;
};class Student :public Person
{
public:virtual void BuyTicket(){std::cout << "Student->半价票" << std::endl;}
private:int age;char gender;
};class Soldier :public Person
{
public:virtual void BuyTicket(){std::cout << "Soldier->军人优先" << std::endl;}
private:int age;char gender;
};void Buy_ticket(Person& p)
{p.BuyTicket();
}int main()
{Person per;Student stu;Soldier soldier;Buy_ticket(per);Buy_ticket(stu);Buy_ticket(soldier);return 0;
}

在这里插入图片描述
运行结果如上,不同对象调用同一个函数,实现各自的方法,如何做到的?分析如下:
在这里插入图片描述

总结一句话
多态实现过程中:指向谁调用谁,指向的对象是哪个,在运行时就指向该对象的虚函数表中去找到对应的虚函数地址,然后根据地址进行函数调用。

4.4、动态绑定和静态绑定

什么是动态绑定和静态绑定?
在这里插入图片描述

4.5、再探虚函数表

  1. 类里面所有的虚函数地址都会存储到虚函数表中去,要注意的是不同类型对象的虚函数表中存放自己对象所对应类中的虚函数地址(不同类型的对象,虚函数表是各自独立的),那么同一类型的对象,虚函数表是共用的。下面通过调试来看:
    在这里插入图片描述
  1. 明确派生类是由两部分构成的,即继承下来的基类和自己的成员,根据一般情况下来看,继承下来的基类中含有虚函数表指针,派生类就不会另外生成虚函数表指针了。这里得注意的是,继承下来的虽然是基类中的虚函数表指针,但是和基类中本身的虚函数表指针不是同一个,也就是说不是同一个空间的,都是各自的了。如下面调试图:
    在这里插入图片描述
  1. 从第2点的图中看到继承下来的虚函数地址也是和基类中的不一样的,因此可以得出在派生类继承基类的过程中因为是重写了基类的虚函数的,又由于是派生类,从第1条中不同类中的虚函数表是各自独立的这个内容来看,因此可以这样理解:派生类虽然继承了基类的虚函数表指针,但是派生类重写了基类的虚函数,作为派生类也可以说是新的一个类,因此有自己的虚函数表指针和虚函数地址,只不过是把自己的虚函数表指针和虚函数地址写到了继承下来的虚函数表指针中的。一句话说明就是:派生类用自己的虚函数表指针覆盖到继承下来的虚函数表指针中去了
  1. 派生类的虚函数表中是包含了基类的虚函数地址、派生类自己重写的虚函数地址(只不过是覆盖到了继承下来的虚函数表中所重写的那个虚函数地址了)、还有就是好派生类自己原本有的虚函数地址。看下图:
    在这里插入图片描述

5.在这里插入图片描述
在这里插入图片描述
代码如下:

#include<iostream>
class Base {
public:virtual void func1() { std::cout << "Base::func1" << std::endl; }virtual void func2() { std::cout << "Base::func2" << std::endl; }void func5() { std::cout << "Base::func5" << std::endl; }
protected:int a = 1;
};
class Derive : public Base
{
public:// 重写基类的func1virtual void func1() { std::cout << "Derive::func1" << std::endl; }virtual void func3() { std::cout << "Derive::func1" << std::endl; }void func4() { std::cout << "Derive::func4" << std::endl; }
protected:int b = 2;
};int main()
{int i = 0;static int j = 1;int* p1 = new int;const char* p2 = "xxxxxxxx";printf("栈:%p\n", &i);printf("静态区:%p\n", &j);printf("堆:%p\n", p1);printf("常量区:%p\n", p2);Base b;Derive d;Base* p3 = &b;Derive* p4 = &d;printf("Person虚表地址:%p\n", *(int*)p3);printf("Student虚表地址:%p\n", *(int*)p4);printf("虚函数地址:%p\n", &Base::func1);printf("普通函数地址:%p\n", &Base::func5);return 0;
}

在这里插入图片描述

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

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

相关文章

【计算机方向】中科院二区TOP神刊!国人发文友好,刊文量高,录用容易!

期刊解析 &#x1f6a9;本 期 期 刊 看 点 &#x1f6a9; 中科院二区TOP期刊&#xff01; 审稿友好&#xff0c;IF4.8&#xff0c;自引率6.2% 最新年度发文530。 今天小编带来计算机领域SCI快刊的解读&#xff01; 如有相关领域作者有意投稿&#xff0c;可作为重点关注&am…

SpringBoot日志集成-LogBack

Log4J&#xff1a;最早的Java日志框架之一&#xff0c;由Apache基金会发起&#xff0c;提供灵活而强大的日志记录机制JDK自带的日志框架&#xff1a;java.util.logging.Logg&#xff0c;是JDK1.4之后提供的日志API&#xff0c;已淘汰logback&#xff1a; logback一个开源的日志…

Java ERP管理系统源码解析:微服务架构实践Spring Cloud Alibaba与Spring Boot

在当今数字化浪潮的推动下&#xff0c;企业对于高效、稳定且易于扩展的管理系统需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的鸿鹄ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、S…

猫头虎 分享已解决Bug: || Module not found: Can‘t resolve ‘react‘ 解决方案

&#x1f42f;猫头虎 分享已解决Bug&#xff1a; || Module not found: Cant resolve react 解决方案 摘要: 今天猫头虎带大家解决一个常见的前端问题&#xff0c;尤其是在 React 项目中&#xff0c;很多开发者在安装依赖包时&#xff0c;遇到过 Module not found: Cant resol…

2024年9月第4周AI资讯

阅读时间&#xff1a;3-4min 更新时间&#xff1a;2024.9.23-2024.9.27 目录 o1 处于OpenAI的AGI5阶段的第2阶段 微软使用核燃料推动AI发展 阿里巴巴和英伟达在自动驾驶方向合作 Meta 推出 AR xAI 眼镜、新型号 o1 处于OpenAI的AGI5阶段的第2阶段 概要 OpenAI 首席执行官 …

智能抠图怎么操作?4款不动手自动抠图的智能神器分享

对于资深的图片设计师们来说&#xff0c;抠图是他们必备的基础技能&#xff0c;没几下功夫就能在PS中操作完成。 然而对于小编这种修图小白来讲&#xff0c;拥有一款傻瓜式智能抠图免费软件&#xff0c;才是硬道理&#xff01; 小到简单的图形文字、大到飞扬细碎的毛发&#…

MySQL第11讲--多表查询的介绍

文章目录 前言多表关系多表查询概述多表查询的分类连接查询内链接外链接自连接 联合查询子查询标量子查询列子查询行子查询表子查询 前言 在MySQL第10讲–约束的介绍中讲了数据库的几种约束条件&#xff1a;非空约束、唯一约束、主键约束、外键约束、检查约束、默认约束。下图对…

Splashtop 加入 Microsoft 智能安全协会

2024年9月25日 美国加利福尼亚州库比蒂诺 Splashtop Inc . 今天宣布已正式加入 Microsoft 智能安全协会&#xff08;MISA&#xff09;。MISA 由独立软件供应商&#xff08;ISV&#xff09;和托管安全服务提供商&#xff08;MISA&#xff09;组成&#xff0c;他们将其解决方案与…

渗透测试-文件上传绕过思路

文件上传绕过思路 引言 分享一些文件上传绕过的思路&#xff0c;下文内容多包含实战图片&#xff0c;所以打码会非常严重&#xff0c;可多看文字表达&#xff1b;本文仅用于交流学习&#xff0c; 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#x…

深度解析APP软件开发:构建卷轴式分销系统的实践探索

在移动互联网的浪潮中&#xff0c;APP软件的开发与应用不断推动着商业模式的创新与发展。其中&#xff0c;卷轴模式分销系统作为一种新兴的营销手段&#xff0c;正逐渐受到市场的青睐。作为程序员&#xff0c;深入探索并实践这一模式的系统开发&#xff0c;不仅是对技术能力的挑…

C++ STL初阶(14): map和set

1.关联式容器与键值对 前导文章&#xff1a;C 二叉树进阶-CSDN博客 之前我们学习的线性的容器&#xff0c;如&#xff1a;vector deque list等都叫作序列式容器 与之对立的概念是关联式容器 关联式容器 也是用来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;其 里面…

【Linux】图解详谈HTTPS的安全传输

文章目录 1.前置知识2.只使用对称加密3.只使用非对称加密 因为私钥加密只能公钥解开&#xff0c;公钥加密只能私钥解开4.双方都是使用非对称加密5.非对称加密 对称加密6.非对称加密对称加密CA认证&#xff08;一&#xff09;CA认证&#xff08;二&#xff09;https &#xff0…

Ks渲染做汽车动画吗?汽车本地渲染与云渲染成本分析

Keyshot是一款强大的实时光线追踪和全域光渲染软件&#xff0c;它确实可以用于制作汽车动画&#xff0c;包括汽车模型的渲染和动画展示。Keyshot的动画功能允许用户创建相机移动、物体变化等动态效果&#xff0c;非常适合用于汽车动画的制作。 至于汽车动画的渲染成本&#xff…

手机如何五开玩梦幻西游端游?用GameViewer远程手机免费畅玩梦幻西游

用手机就能免费玩梦幻西游端游&#xff0c;还可以随时查看挂机进度&#xff01; 想要实现这一点&#xff0c;就用网易GameViewer远程&#xff0c;而且不光手机可以玩梦幻西游端游&#xff0c;平板也能免费玩&#xff0c;并为你实现五开玩梦幻西游端游。 那么&#xff0c;通过Ga…

[001-03-007].第28节:SpringBoot整合Redis:

6.1.Redis的介绍&#xff1a; 1.Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。2.它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c; 散…

Python制作进度条,18种方式全网最全!(不全去你家扫厕所!)

想象一下&#xff0c;你的程序在执行复杂任务时&#xff0c;不再是冷冰冰的等待光标&#xff0c;而是伴随着色彩斑斓、动态变化的进度条&#xff0c;不仅让等待变得有趣&#xff0c;更让用户对你的作品刮目相看。从基础的文本进度条到高级的图形界面进度条&#xff0c;从简单的…

Excel FIND函数用法详解,附FIND函数提取文本示例

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f50e; 在处理文本数据时&#xff0c;我们经常需要在字符串中查找特定词语或字符的位置。Excel中的FIND函数是一个非常实用的工具&#xff0c;可以帮助我们在文本字符串中查找子字符串的位置。今天&#xff0c;我们将…

Ubuntu环境下字体安装

本文介绍Ubuntu环境下字体安装。 软件&#xff08;如Qt应用软件&#xff09;开发过程中经常会涉及到字体的选择&#xff0c;有时候Ubuntu环境下并没有我们想要的字体&#xff0c;本文介绍常用字体及在Ubuntu环境下如何安装。 1.常用开源字体 有些字体商用并不是免费的&#…

【解答篇】什么是SSL证书?它为什么很重要?

什么是SSL证书&#xff1f;它为什么很重要&#xff1f; 1 数据保护的金钟罩2 身份验证的守护者3 信任度与SEO的双重提升4 合规经营的必要条件5 某宝案例 SSL证书&#xff0c;全称安全套接层证书&#xff0c;是互联网安全通信的坚固基石。它并非仅仅是一份文档&#xff0c;而是用…

落魄前端搞副业之 改造淘宝首页(淘宝换肤)

事情发生是这样的: 无意间看到一个淘宝的网页版本换肤大赛, 本来我也是不懈看一眼的. 一脸高傲. 因为各种比赛, 要么就是对手太厉害, 拿不到奖, 要么就是主办方潜规则多, 最终坑人. 那, 按照我的性子, 那必然不会参加啊, /高傲 (奖金不多, 设计开发麻烦, 竞争还大, 说不定还…