【C++】---多态

【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. 什么是抽象类?抽象类的作用?

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

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

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

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


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s集群中pod的容器资源限制和三种探针

一、资源限制 总结&#xff1a; requests表示创建pod时预留的资源&#xff0c;limits表示pod能够使用资源的最大值。requests值可以被超&#xff0c;limits值不能超过&#xff0c;如果是内存使用超过limits会触发oom然后杀掉进程&#xff0c;如果是cpu超过limits会压缩cpu的使用…

Hudi 多表摄取工具 HoodieMultiTableStreamer 配置方法与示例

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

【Linux初探】:解锁开源世界的神秘钥匙

文章目录 &#x1f680;一、了解Linux&#x1f525;二、Linux 的发行版❤️三、Linux应用领域&#x1f4a5;四、Linux vs Windows & mac &#x1f680;一、了解Linux Linux是一种自由、开放源代码的操作系统&#xff0c;它的内核由芬兰计算机科学家Linus Torvalds在1991年创…

【九十四】【算法分析与设计】练习四蛮力法练习,排列问题和组合问题,求解最大连续子序列和问题,求解幂集问题,求解0/1背包问题,求解任务分配问题

求解最大连续子序列和问题 给定一个有n&#xff08;n≥1&#xff09;个整数的序列&#xff0c;要求求出其中最大连续子序列的和。 例如&#xff1a; 序列&#xff08;-2&#xff0c;11&#xff0c;-4&#xff0c;13&#xff0c;-5&#xff0c;-2&#xff09;的最大子序列和为20…

机器人支持回调接口配置(详细教程)

大家伙&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 一、前言 今天&#xff0c;给大家介绍一下&#xff0c;如何在机器人中配置回调地址和接口编写。很多时候我们可能有这样的场景&#xff0c;收到消息后&#xff0c;想自己处理一下消息的内…

用Python一键生成PNG图片的PowerPoint幻灯片

在当今的商业环境中,PowerPoint演示是展示和传递信息的常用方式。然而,手动将大量图像插入到幻灯片中往往是一项乏味且耗时的工作。但是,通过Python编程,我们可以轻松自动化这个过程,节省时间和精力。 C:\pythoncode\new\folderTOppt.py 在本文中,我将介绍如何使用Python、wx…

Rust开源Web框架Salvo源码编译

1.克隆源码: https://github.com/salvo-rs/salvo.git 2.进入salve目录并运行cargo build编译 编译成功 3.编译生成的库 4.安装salve-cli git clone --recursive https://github.com/salvo-rs/salvo-cli.git 编译salve-cli

人工智能万卡 GPU 集群的硬件和网络架构

万卡 GPU 集群互联:硬件配置和网络设计 一、背景 自从 OpenAI 推出 ChatGPT 以来,LLM 迅速成为焦点关注的对象,并取得快速发展。众多企业纷纷投入 LLM 预训练,希望跟上这一波浪潮。然而,要训练一个 100B 规模的 LLM,通常需要庞大的计算资源,例如拥有万卡 GPU 的集群。以…

Google Play 提示 “您的设备与此版本不兼容“ 解决方案

一、 问题概述Google Play提示“您的设备与此版本不兼容”&#xff0c;无法安装应用。 遇到问题的设备为Xiaomi Mi A3&#xff0c;查了下这台手机的基本信息&#xff0c;Android One系统&#xff0c;版本分为9.0、10.0、11.0。 二、 问题分析Google Play的过滤器 通常有以下5种…

【Nginx <末>】Nginx 基于 IP 地址的访问限制

目录 &#x1f44b;前言 &#x1f4eb;一、限制 IP 可以实现哪些功能 &#x1f440;二、 项目实现 2.1 访问控制实现 2.2 Nginx 配置中指定 IP 地址 &#x1f49e;️三、章末 &#x1f44b;前言 小伙伴们大家好&#xff0c;前面一段时间学习了 Nginx 的相关知识&#xff0c…

RT-DRET在实时目标检测上超越YOLO8

导读 目标检测作为计算机视觉的核心任务之一&#xff0c;其研究已经从基于CNN的架构发展到基于Transformer的架构&#xff0c;如DETR&#xff0c;后者通过简化流程实现端到端检测&#xff0c;消除了手工设计的组件。尽管如此&#xff0c;DETR的高计算成本限制了其在实时目标检测…

React useState基本类型变量的使用

在 React 中&#xff0c;useState 是一个 Hook&#xff0c;用于在函数组件中添加状态&#xff0c;它可以让函数组件拥有状态。基本使用方法如下&#xff1a; // App.jsx import React, { useState } from reactfunction App() {// 使用 useState 创建一个状态变量&#xff0c;初…

如何用Java实现SpringCloud Alibaba Sentinel的熔断功能?

在Java中使用Spring Cloud Alibaba Sentinel实现熔断功能的步骤如下&#xff1a; 添加依赖 在项目的pom.xml文件中添加Spring Cloud Alibaba Sentinel的依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud…

C语言——malloc和free用法和常见误区

最近写了个关于动态数组的代码&#xff0c;遇到了一个大坑&#xff0c;特此记录 先说结论&#xff1a; 1.利用malloc创建堆空间&#xff0c;大小最好设置大一点&#xff0c;不然后面存进去的值需要的空间过大会导致各种的堆、指针问题 2.只能使用realloc对已经创建的空间进行修…

没有电商经验的人去操作抖音小店,难度大不大?好操作吗?

大家好&#xff0c;我是电商小V 很多新手小伙伴想去操作抖音小店项目&#xff0c;咨询的最多的问题就是我没有电商运营的经验可以去操作吗&#xff1f; 当然是可以操作的&#xff0c;抖音小店项目对于新手来说是一个非常友好的项目&#xff0c;很多小伙伴都是感觉没有电商经验去…

C++——list的实现以及源码

前言&#xff1a; 最近学习了clist的实现&#xff0c;这让我对迭代器的理解又上升了一个新的高度&#xff0c;注意&#xff1a;代码里的list是放在一个叫zgw的命名空间里边&#xff0c;但是在实现list的代码中没有加namespace&#xff0c;这里给个注意&#xff0c;以后复习时能…

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

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

五分钟搭建一个Suno AI音乐站点

五分钟搭建一个Suno AI音乐站点 在这个数字化时代&#xff0c;人工智能技术正以惊人的速度改变着我们的生活方式和创造方式。音乐作为一种最直接、最感性的艺术形式&#xff0c;自然也成为了人工智能技术的应用场景之一。今天&#xff0c;我们将以Vue和Node.js为基础&#xff…

三十六计的笔记

系列文章目录 三十六计的笔记 文章目录 系列文章目录1、瞒天过海2、围魏救赵3、借刀杀人4、以逸待劳5、趁火打劫6、声东击西7、无中生有8、暗渡陈仓9、隔岸观火10、笑里藏刀11、李代桃僵12、顺手牵羊13、打草惊蛇14、借尸还魂15、调虎离山16、欲擒故纵17、抛砖引玉18、擒贼擒王…

牛客NC302 环形数组的连续子数组最大和【中等 动态规划 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/e9f3282363844355aa51497c5410beee 思路 动态规划 两种情况&#xff08;首位相连的&#xff09;和首位不相连的 首尾相连的可以算最小的连续子数组得出&#xff0c;sum-就是。Java代码 import java.util.*;pub…