【c++】cpp类的继承

目录

(1)继承概念与语法

(2)派生类的访问控制

(3)继承中的构造和析构

1.类型兼容性原则

2.继承中的构造析构调用原则

3.继承与组合混搭下构造和析构调用原则

(4)同名成员(函数)的继承

(5)static成员的继承

(6)多继承与虚继承

1.多继承的语法

2.多继承的二义性

3.用虚继承解决二义性

4.虚继承的实现原理

5.虚继承解决二义性的作用也有限


(1)继承概念与语法

类之间的关系:has-A,uses-A 和 is-A

  • has-A   包含关系,⽤以描述⼀个类由多个“部件类”构成。实现has-A关系⽤类成员表示, 即⼀个类中的数据成员是另⼀种已经定义的类。
  • uses-A  ⼀个类部分地使⽤另⼀个类。通过类之间成员函数的相互联系,定义友员或对象参 数传递实现。
  • is-A   机制称为“继承”。关系具有传递性,不具有对称性。

继承是类之间定义的一种重要关系。一个B类继承A类,或称从类A派生类B。类A称为基类(父类),类B称为派生类(子类)。

继承的重要作用就在于随着业务的不断变化,提出了新的业务需求,需要开发新的类,但又仍需要父类的某些功能,因此有了继承这个概念,子类继承自父类,可以继续使用父类的某些属性或者功能,同时又能有专属自己的功能。

类继承的语法

// 单继承
class 子类名: 访问控制关键字 父类名
{数据成员和成员函数声明
};// 多继承
class 子类名: 访问控制关键字 父类名1, 访问控制关键字 父类名2, ...
{数据成员和成员函数声明
};

访问控制关键字表示子类对父类的继承方式:

public    公有继承
private   私有继承
protected 保护继承

继承重要说明

  • ⼦类拥有⽗类的所有成员变量和成员函数
  • ⼦类可以拥有⽗类没有的⽅法和属性
  • ⼦类就是⼀种特殊的⽗类
  • ⼦类对象可以当作⽗类对象使用(比如函数参数要求传递父类对象,传递子类对象也可)

如何访问继承的成员或者函数:假设a是父类Parent的成员,child为Child的实例化对象,则可以通过这两种方式访问:

  • child.Parent::a
  • child.a

关于继承方式:采用不同的继承方式会影响从父类手中接盘资产的访问属性,这个将在下一节讲解,这里以public继承为例,子类将原封不动地接盘父类的全部资产,且资产属性不变。

示例代码

#include <iostream>class Parent
{
public:int b;
public:void print(){a = 0;b = 0;std::cout << "a = " << a << std::endl;std::cout << "b = " << b << std::endl;}private:int a;
protected:
};// 子类继承父类
// class Child : private Parent
// class Child : protected Parent
class Child : public Parent
{
public:
private:int c;
protected:
};int main()
{Child c1;c1.print();std::cout << "c1.b = " << c1.b << std::endl;// 也可以这样访问继承的成员std::cout << "c1.b = " << c1.Parent::b << std::endl; return 0;
}

运行结果

a = 0
b = 0
c1.b = 0
c1.b = 0

(2)派生类的访问控制

1.理解成员属性

  • public: 修饰的成员变量⽅法 ,在类的内部和类的外部都能使⽤
  • protected: 修饰的成员变量⽅法,在父类和子类的内部可⽤ ,在外部不能被使⽤
  • private: 修饰的成员变量⽅法,只能在类的内部使⽤,不能在类的外部,不可继承

2.不同的继承方式会改变继承成员的访问属性

派⽣类继承了基类的全部成员变量和成员方法(除了构造和析构之外的成员方法),但是这些成 员的访问属性,在派生过程中是可以调整的。

  • public继承:⽗类成员在⼦类中保持原有访问级别
  • private继承:⽗类成员在⼦类中变为private成员
  • protected继承:
    • 父类中public成员会变成protected
    • ⽗类中protected成员仍然为protected
    • ⽗类中private成员仍然为private

注意:private成员在⼦类中依然存在,但是却⽆法访问到。不论种⽅式继承基类,派⽣类都不能直接 使⽤基类的私有成员。

项目开发中 一般情况下 是 class B : public A。

示例代码

#include <iostream>
#include <string>class Parent
{
public:Parent(){name = "parent";password = 123;emotion_friend = 0;}
public:std::string name;    //老爹的名字
protected:int password;        //老爹的银行密码
private:int emotion_friend;   //老爹的情人 // 私有的无论怎样继承,儿子都没法访问
};// 公有继承
class Child1 : public Parent
{
public:void useVar(){std::cout << name << std::endl;  // okstd::cout << password << std::endl;  // ok// std::cout << emotion_friend << std::endl;  // errorreturn;}
};// 私有继承
class Child2 : private Parent
{
public:void useVar(){std::cout << name << std::endl;  // okstd::cout << password << std::endl;  // ok// std::cout << emotion_friend << std::endl;  // errorreturn;}
};// 保护继承
class Child3 : protected Parent
{
public:void useVar(){std::cout << name << std::endl;  // okstd::cout << password << std::endl;  // ok// std::cout << emotion_friend << std::endl;  // errorreturn;}
};int main()
{// 1.公有继承std::cout << "----------------" << std::endl;Child1 c1;c1.name = "child1"; // ok// c1.password = 456; // err,因为protected不能外部访问// c1.emotion_friend = 1; // err,因为private不能外部访问c1.useVar();// 2.私有继承std::cout << "----------------" << std::endl;Child2 c2;// c2.name = "child1"; // err,因为private不能外部访问// c2.password = 456; // err,因为private不能外部访问// c1.emotion_friend = 1; // err,因为private不能外部访问c2.useVar();// 3.保护继承std::cout << "----------------" << std::endl;Child3 c3;// c3.name = "child1"; // err,因为protected不能外部访问// c3.password = 456; // err,因为protected不能外部访问// c3.emotion_friend = 1; // err,因为private不能外部访问c3.useVar();return 0;
}

运行结果

----------------
child1
123
----------------
parent
123
----------------
parent
123

(3)继承中的构造和析构

1.类型兼容性原则

类型兼容规则是指在需要基类对象的任何地⽅,都可以使⽤公有派⽣类的对象来替代。通过公有 继承,派⽣类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具 备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。

类型兼容规则中所指的替代包括以下情况:

  • 子类对象可以当作父类对象使用
  • 子类对象可以直接赋值给父类对象
  • 子类对象可以直接初始化父类对象
  • 父类指针可以直接指向子类对象
  • 父类引⽤可以直接引用子类对象

在替代之后,派生类对象就可以作为基类的对象使⽤,但是只能使用从基类继承的成员。

总结:子类就是特殊的⽗类 (base *p = &child;)

#include <iostream>
#include <string>class Parent
{
public:void printP(){std::cout << "I'm Parent" << std::endl;}
public:Parent(){std::cout << "Parent Normal Generate Func" << std::endl;}Parent(Parent &obj){std::cout << "Parent Copy Generate Func" << std::endl;}
private:int a;
};class Child : public Parent
{
public:void printC(){std::cout << "I'm Child" << std::endl;}
protected:
private:int c;
};void PrintParent(Parent *p)
{p->printP();
}
void PrintParent(Parent &base)
{base.printP();
}int main()
{Parent parent1;   // Parent Normal Generate Funcparent1.printP(); // I'm Parent// 使用继承来的成员Child child1;    // Parent Normal Generate Funcchild1.printC(); // I'm Childchild1.printP(); // I'm Parent//父类指针指向子类对象Parent *p = NULL;p = &child1;p->printP(); // I'm Parent//指针做函数参数PrintParent(&parent1); //I'm ParentPrintParent(p);   //I'm Parent//引用做函数PrintParent(child1); //I'm ParentPrintParent(parent1); //I'm Parent//子类对象 初始化 父类对象Parent parent2 = child1; // Parent Copy Generate Funcparent2.printP();    //I'm Parentreturn 0;
}

2.继承中的构造析构调用原则

问题:如何初始化父类成员?父类与子类的构造函数有什么关系

  • 在子类对象构造时,需要调用父类构造函数对其继承得来的成员进⾏初始化
    • 子类对象在创建时会首先调⽤父类的构造函数
    • 父类构造函数执行结束后,执行子类的构造函数
    • 当父类的构造函数有参数时,需要在子类的初始化列表中显示调⽤
  • 在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理
    • 析构函数调⽤的先后顺序与构造函数相反

示例代码

#include <iostream>class Parent
{
public:Parent(int a = 0, int b = 0){this->a = a;this->b = b;std::cout << "Parent Normal Generate Func" << std::endl;}Parent(const Parent &obj){std::cout << "Parent Copy Generate Func" << std::endl;}~Parent(){std::cout << "Parent Destroyed Func" << std::endl;}
private:int a;int b;
};class Child : public Parent
{
public:Child(int a, int b, int c):Parent(a, b){this->c = c;std::cout << "Child Normal Generate Func" << std::endl;}~Child(){std::cout << "Child Destroyed Func" << std::endl;}
protected:
private:int c;
};int main()
{Child c1(1, 2, 5);return 0;
}

运行结果

Parent Normal Generate Func
Child Normal Generate Func
Child Destroyed Func
Parent Destroyed Func

3.继承与组合混搭下构造和析构调用原则

构造顺序:先祖宗类构造 → 父类构造 → 成员变量构造 → 再自己构造

析构顺序:先自己析构 → 再成员变量析构 → 再父类析构 → 再祖宗类析构

示例代码

#include <iostream>// 祖宗类
class GrandParent
{
public:GrandParent(int a, int b){this->a = a;this->b = b;std::cout << "GrandParent Normal Generate Func: " << a << "," << b << std::endl;}~GrandParent(){std::cout << "GrandParent Destroyed Func" << std::endl;}
private:int a;int b;
};// 父类,继承于祖宗类
class Parent: public GrandParent
{
public:Parent(char *p): GrandParent(1, 2){this->p = p;std::cout << "Parent Normal Generate Func:  " << p << std::endl;}~Parent(){std::cout << "Parent Destroyed Func" << std::endl;}
private:char *p;
};// 子类,继承于父类
class Child : public Parent
{
public:Child(char *p):Parent(p), gp1(3, 4), gp2(5, 6){this->cp = p;std::cout << "Child Normal Generate Func:   " << p << std::endl;}~Child(){std::cout << "Child Destroyed Func" << std::endl;}
public:
protected:char *cp;GrandParent gp1;GrandParent gp2;
};int main()
{char data[] = "test";std::cout << "-----------Generate-----------" << std::endl;Child c1(data);std::cout << "-----------Destroy-----------" << std::endl;return 0;
}

运行结果

-----------Generate-----------
GrandParent Normal Generate Func: 1,2
Parent Normal Generate Func:  test
GrandParent Normal Generate Func: 3,4
GrandParent Normal Generate Func: 5,6
Child Normal Generate Func:   test
-----------Destroy-----------
Child Destroyed Func
GrandParent Destroyed Func
GrandParent Destroyed Func
Parent Destroyed Func
GrandParent Destroyed Func

(4)同名成员(函数)的继承

当子类成员变量与父类成员变量同名时

  • 子类依然从⽗类继承同名成员
  • 在⼦类中通过作⽤域分辨符 :: 进⾏同名成员区分。在⼦类外部⽤ childObj.Parent::name 和 childObj.Child::name,在⼦类内部⽤Parent::name和Child::name。
  • 同名成员变量和成员函数通过作⽤域分辨符进⾏区分。调⽤name默认是childObj.Child::name和 Child::name。
  • 同名成员存储在内存中的不同位置

示例代码

#include <iostream>class Parent
{
public:Parent(int a = 0, int b = 0){this->a = a;this->b = b;}
public:void print(){ std::cout << "print parent" << std::endl;}void get(){ std::cout << "a=" << a << ",b=" << b << std::endl;}
public:int a;int b;
};class Child : public Parent
{
public:Child(int a=0, int b=0, int c=0):Parent(a, b){this->b = b;this->c = c;}
public:void print(){ std::cout << "print child" << std::endl;}void get(){ std::cout << "a=" << a << ",b=" << b << ",c=" << c << std::endl;}
public:int b;int c;};int main()
{Child c1(1, 2, 3);// 1.同名变量std::cout << c1.b << std::endl;         // 2std::cout << c1.Child::b << std::endl;  // 2std::cout << c1.Parent::b << std::endl; // 2//修改父类的bc1.Parent::b = 100;std::cout << c1.Parent::b << std::endl; // 100std::cout << c1.Child::b << std::endl;  // 2std::cout << c1.b << std::endl;         // 2// 2.同名函数c1.print();         // print childc1.Child::print();  // print child //默认情况c1.Parent::print(); // print parentc1.get();         // a=1,b=2,c=3c1.Child::get();  // a=1,b=2,c=3c1.Parent::get(); // a=1,b=100return 0;
}

(5)static成员的继承

  • 基类定义的静态成员,将被所有派生类共享
  • 根据静态成员自身的访问特性和派生类的继承⽅式,在类层次体系中具有不同的访问性质 (遵守派生类的访问控制)
  • 在派生类的内部访问静态成员,直接变量名即可:
  • 在派生类中的外部访问静态成员,⽤以下形式:
    • 类名 :: 成员
    • 对象名 . 成员

示例代码

#include <iostream>class Parent
{
public:Parent(){std::cout << "Parent generate func" << std::endl;}
public:void printa(){std::cout << "class Parent call: static a=" << a << std::endl;}
public:static int a;int b;
protected:
private:
};// 静态变量的初始化
int Parent::a = 100; //这句话 不是简单的变量赋值
// 更重要的是 要告诉C++编译器 你要给我分配内存
// 我在继承类中 用到了a 不然会报错..class Child : private Parent
{
public:Child(){std::cout << "Child generate func" << std::endl;}
public:void printa(){std::cout << "class Child call: static a=" << a << std::endl;}
public:int b;int c;
protected:
private:
};// 1 static关键字 遵守  派生类的访问控制规则
// 2 不是简单的变量赋值 更重要的是 要告诉C++编译器
// 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..void objplay()
{Parent parent1;         parent1.printa();  Child child1;        child1.printa();// child1.a = 200; //非法,因为是私有继承,只能在类的内部共享std::cout << Parent::a << std::endl;  // 访问同一个静态成员std::cout << parent1.a << std::endl;  // 访问同一个静态成员// std::cout << child1.a << std::endl;  // 将会error,因为私有继承
}int main()
{objplay();return 0;
}

运行结果

Parent generate func
class Parent call: static a=100
Parent generate func
Child generate func
class Child call: static a=100
100
100

(6)多继承与虚继承

1.多继承的语法

多继承的派生类构造和访问
  • 多个基类的派生类构造函数可以用初始化列表调用基类构造函数初始化数据成员
  • 执⾏顺序与单继承构造函数情况类似。多个直接基类构造函数执⾏顺序取决于定义派⽣类时 指定的各个继承基类的顺序。
  • ⼀个派⽣类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现⼆义性。如果不 同的基类有同名成员,派⽣类对象访问时应该加以识别。
示例代码
#include <iostream>class Base1
{
public:Base1(int b1){std::cout << "Base1 generate func" << std::endl;this->b1 = b1;}~Base1(){std::cout << "Base1 destroy func" << std::endl;}void printB1(){std::cout << "b1:" << b1 << std::endl;;}
protected:
private:int b1;
};class Base2
{
public:Base2(int b2){std::cout << "Base2 generate func" << std::endl;this->b2 = b2;}~Base2(){std::cout << "Base2 destroy func" << std::endl;}void printB2(){std::cout << "b2:" << b2 << std::endl;;}
protected:
private:int b2;
};class Child : public Base1, public Base2
{
public:Child(int b1, int b2, int c) : Base2(b2), Base1(b1){std::cout << "Child generate func" << std::endl;this->c = c;}~Child(){std::cout << "Child destroy func" << std::endl;}void printC(){std::cout << "c:" << c << std::endl;;}
protected:
private:int c;
};int main()
{Child c1(1, 2, 3);c1.printC();c1.printB1();c1.printB2();return 0;
}

运行结果

Base1 generate func
Base2 generate func
Child generate func
c:3
b1:1
b2:2
Child destroy func
Base2 destroy func
Base1 destroy func

2.多继承的二义性

示例代码

#include <iostream>class B
{
public:int b;
};class B1 : public B
{
public:int b1;
};class B2 : public B
{
public:int b2;
};class C : public B1, public B2
{
public:int c;
};int main()
{C c1;c1.b1 = 100;c1.b2 = 200;c1.c = 300;// c1.b = 500; //这句会报错,因为二义性,//  到底是B1的的b,还是B2的b分不清return 0;
}

3.用虚继承解决二义性

  • 如果⼀个派生类从多个基类派⽣,⽽这些基类⼜有⼀个共同的基类,则在对该基类中声明的 名字进⾏访问时,可能产⽣⼆义性
  • 如果在多条继承路径上有⼀个公共的基类,那么在继承路径的某处汇合点,这个公共基类就 会在派生类的对象中产生多个基类子对象
  • 要 使这个公共基类在派生类中只产生⼀个子对象,必须对这个基类声明为虚继承,使这个基 类成为虚基类
  • 虚继承声明使用关键字:virtual

像下面这样

示例代码

#include <iostream>class B
{
public:int b;
};class B1 : virtual public B
{
public:int b1;
};class B2 : virtual public B
{
public:int b2;
};class C : public B1, public B2
{
public:int c;
};int main()
{C c1;c1.b1 = 100;c1.b2 = 200;c1.c = 300;c1.b = 500; //因为virtual继承,这里将不会再报错std::cout << c1.B1::b << std::endl;  // 500c1.B1::b = 600;std::cout << c1.b << std::endl; // 600c1.B2::b = 700;std::cout << c1.b << std::endl; // 700c1.B::b = 1000;std::cout << c1.b << std::endl; // 1000return 0;
}

4.虚继承的实现原理

如果继承的多个基类有⼀个共同的基类,则⽤虚继承时只会把⽼祖宗的构造函数只只执⾏⼀次, 而不是执行多次使得产生⼆义性。

示例代码

#include <iostream>class B
{
public:B(){std::cout << "B copy generate func" << std::endl;}int b;
};class B1 : virtual public B
{
public:int b1;
};class B2 : virtual public B
{
public:int b2;
};class B3 : virtual public B
{
public:int b3;
};class B4 : virtual public B
{
public:int b4;
};class C1 : public B1, public B2
{
public:int c1;
};class C2 : public B3, public B4
{
public:int c2;
};int main()
{//加上virtual以后 , C++编译器会在给变量偷偷增加属性std::cout << "----------------------" << std::endl;std::cout << sizeof(B) << std::endl;std::cout << sizeof(B1) << std::endl;std::cout << sizeof(B2) << std::endl;std::cout << sizeof(B3) << std::endl;std::cout << sizeof(B4) << std::endl;std::cout << "----------------------" << std::endl;C1 c1;c1.b1 = 100;c1.b2 = 200;std::cout << "----------------------" << std::endl;C2 c2;c2.b3 = 500;c2.b4 = 600;c2.b = 700;c2.B3::b3 = 1000;c2.B::b = 99;return 0;
}

运行结果

----------------------
4
16
16
16
16
----------------------
B copy generate func
----------------------
B copy generate func

5.虚继承解决二义性的作用也有限

对于下图右边这种多继承,虚继承也无法解决⼆义性。

只能通过作用域符号来明确,c.B1::k,c.B2::k


end

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

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

相关文章

slice

最重要的一张图 endlessSummer :summer[:5]//这是这张图真正厉害的地方为什么向函数传递slice允许在函数内部修改底层数组的元素&#xff1f; 因为slice值包含指向第一个sllice元素的指针&#xff0c;传入的slice允许在函数内部修改底层数组的元素。 复制的slice只是对底层的…

LabVIEW与Modbus协议的多点温度监控系统

LabVIEW与Modbus协议的多点温度监控系统 随着工业自动化和智能化水平的不断提升&#xff0c;对于现场监控技术的需求日益增长。开发了一种基于LabVIEW与Modbus协议的多点温度监控系统&#xff0c;实现高效、准确的温度数据采集、处理和显示&#xff0c;以及数据存储功能&#…

TCP/IP协议族中的TCP(一):解析其关键特性与机制

⭐小白苦学IT的博客主页⭐ ⭐初学者必看&#xff1a;Linux操作系统入门⭐ ⭐代码仓库&#xff1a;Linux代码仓库⭐ ❤关注我一起讨论和学习Linux系统 前言 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字…

牛客社区帖子分页显示实现

下图是前端分页的组件&#xff1a; 下面是对应的静态html页面&#xff0c;每一个方块&#xff0c;都是一个a标签&#xff0c;可以点击&#xff0c;执行的链接是/community/index&#xff0c;GET请求&#xff0c;拼接的参数是current&#xff0c;也就是pageNum&#xff0c;只需…

力扣HOT100 208. 实现Trie(前缀树)

解题思路&#xff1a; class Trie {private Trie[] children; // 存储子节点的数组private boolean isEnd; // 记录是否为单词结尾public Trie() {children new Trie[26]; // 数组大小为26&#xff0c;代表26个小写字母isEnd false;}public void insert(String word) {Trie …

智能小程序 Ray 开发实践——基础内容组件 Text 和 Icon 介绍

Text 文本内容。 导入 import { Text } from ray-js/ray; Props 属性类型默认值说明支持平台classNamestring样式名涂鸦、微信selectablebooleanfalse文本是否可选涂鸦、微信onClick(e: { type: click }) > voidfalse点击事件涂鸦、微信 示例代码 基本使用 import Re…

【yolov8算法道路-墙面裂缝检测-汽车车身凹陷-抓痕-损伤检测】

yolo算法道路-墙面裂缝检测-汽车车身凹陷-抓痕-损伤检测 1. yolo算法裂缝检测-汽车车身凹陷-抓痕检测-汽车车身损伤检测2. yolo房屋墙面路面裂缝-发霉-油漆脱落-渗水-墙皮脱落检测3. 水泥墙面裂缝检测 YOLOv8算法是一种先进的目标检测技术&#xff0c;它基于YOLO系列算法的改进…

探索矿业数字化平台:实现智能化采矿与管理

随着信息技术的迅猛发展&#xff0c;矿业领域也在逐步实现数字化转型。数字化平台的出现为矿业企业带来了更高效、更智能的采矿与管理方式。本文将探讨矿业数字化平台的意义、特点以及未来发展方向。 ### 1. 数字化平台的意义 传统的矿业生产和管理方式存在诸多问题&#xff…

Python赋值运算符

目录 赋值运算符 将值赋给变量&#xff1a; 做加法运算之后完成赋值&#xff1a; 做减法运算之后完成赋值&#xff1a;- 做乘法运算之后完成赋值&#xff1a;* 做除法运算之后完成赋值&#xff1a;/ 做整除运算之后完成赋值&#xff1a;// 做幂次运算之后完成赋值&#xff1a;*…

Pytorch 计算深度模型的大小

计算模型大小的方法 卷积 时间复杂度 与 空间复杂度 的计算方式&#xff1a; C 通道的个数&#xff0c;K卷积核大小&#xff0c;M特征图大小&#xff0c;C_l-1是输入通道的个数&#xff0c;C_l是输出通道的个数 1 模型大小 MB 计算模型的大小的原理就是计算保存模型所需要…

在MySQL中isnull()函数不能作为替代null值!

在MySQL中isnull()函数不能作为替代null值&#xff01; 如下&#xff1a; 首先有个名字为business的表&#xff1a; SELECT ISNULL(business_name,no business_name) AS bus_isnull FROM business WHERE id2 直接运行就会报错&#xff1a; 错误代码&#xff1a; 1582 Incor…

cuDNN-Graph API

Graph API 为了适应越来越重要的算子融合需求&#xff0c;cuDNN8.0版本引入了Graph API&#xff0c;以提供更灵活的API接口。Graph API提供一个声明式的编程模型&#xff0c;此模型将计算操作描述为计算图。 用户首先需要构建操作图。从高层面来说&#xff0c;用户其实是在描…

Swift - Playground

文章目录 Swift - Playground1. 新建Playground2. View3. 图片4. ViewController5. Playground - 多Page6. 注释6.1 Playground的注释支持markup语法&#xff08;与markdown相似&#xff09;6.1.1 语法 Swift - Playground Playground可以快速预览代码效果&#xff0c;是学习语…

设计模式(九):组合模式

设计模式&#xff08;九&#xff09;&#xff1a;组合模式 1. 组合模式的介绍2. 组合模式的类图3. 组合模式的实现 1. 组合模式的介绍 组合模式&#xff08;Composite Pattern&#xff09;属于结构型模式&#xff0c;是用于把一组相似的对象当作一个单一的对象。 组合模式依据…

基于SpringBoot+Vue校园二手交易系统的设计与实现

系统介绍 自从新冠疫情爆发以来&#xff0c;各个线下实体越来越难做&#xff0c;线下购物的人也越来越少&#xff0c;随之带来的是一些不必要的浪费&#xff0c;尤其是即将毕业的大学生&#xff0c;各种用品不方便携带走导致被遗弃&#xff0c;造成大量的浪费。本系统目的就是让…

基于Spring Boot的旅游管理系统设计与实现

基于Spring Boot的旅游管理系统设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 前台浏览管理界面图&#xff0c;通过内容列表可以获取网…

PotatoPie 4.0 实验教程(41) —— FPGA实现RISC-V 扩展 GPIO UART Timer功能

TD工程介绍 我们提供的TD工程里的RISC-V核默认就开启了GPIO UART扩展&#xff0c;可以看到还有SPI和I2C扩展。因此后面的实验中TD的工程我们基本不怎么修改TD的内容&#xff0c;只需要修改TD工具中Soc_Top.v文件中的TCM0_INITFILE为FD生成的固件名称即可&#xff0c;主要修我以…

【mysql】mysql命令使用大全,你想要的都在这里

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

go设计模式之工厂方法模式

工厂方法模式 什么是工厂方法模式 工厂方法模式是一种创建型设计模式&#xff0c;它定义了一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到其子类。 这个接口就是工厂接口&#xff0c;子类就是具体工厂类&#xff0c;而需要创…

《QT实用小工具·四十三》历史编辑器(支持历史搜索 关键字匹配)

1、概述 源码放在文章末尾 该项目实现了在输入框中输入部分信息能全部展现之前的历史输入信息&#xff0c;支持历史搜索和关键词匹配&#xff0c;项目demo演示如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #include "historymodel.h" #include <QM…