首页 > 其他分享 >继承与接口

继承与接口

时间:2023-08-29 12:36:17浏览次数:26  
标签:类型转换 函数 继承 基类 接口 派生类 构造函数



文章目录

  • 一、重载、重写(覆盖)与隐藏的区别
  • 二、私有继承、公有继承、保护继承
  • 三、多重继承与虚继承
  • 1、多重继承
  • 2、类型转换与多个基类
  • 3、多重继承demo:
  • 4、虚继承
  • 5、虚继承demo:
  • 四、纯虚函数和抽象类
  • 1、面试题--->纯虚函数的实现原理,为什么抽象基类不能被实例化?
  • 2、面试题--->如何阻止一个类被实例化?
  • 五、运算符重载与四种类型转换
  • 1、运算符重载
  • 2、四种类型转换


一、重载、重写(覆盖)与隐藏的区别

  • 重载是指函数名相同,但是函数参数类型或者参数个数不同的一类函数,返回值不能作为重载的标志
  • 重写(覆盖)是指派生类中重新定义的虚函数,函数名、参数列表和函数返回值都和基类相同。
  • 隐藏是指派生类中定义了和基类同名的函数,只要同名就会被隐藏

二、私有继承、公有继承、保护继承

继承与接口_继承

三、多重继承与虚继承

1、多重继承

多重继承是指从多个基类中产生派生类的情况,多重继承的派生类继承了所有父类的属性
  构造一个派生类对象时将会同时构造并初始化它所有的基类子对象,如若不是显示初始化,则其会使用基类的默认构造函数进行初始化,基类的构造顺序与派生类列标准基类出现的顺序一致。
  C++11新标准,派生类可以从其基类中继承构造函数,但是若从所个基类中继承了相同的构造函数(形参列表完全相同的情况),就会发生错误,此时该派生类应该为它自己定义一个形参列表相同的构造函数。
  析构函数执行的顺序与构造函数相反,派生类的析构函数只负责清除派生类本身分配的资源,派生类的成员及基类都是自动销毁的。

2、类型转换与多个基类

可以令某个可访问基类的指针或引用直接指向一个派生类对象,但该指针只能访问其对应的基类部分或者基类的基类部分。
  当一个类拥有多个基类时,有可能从多个类中继承了同名成员的情况,此时需要加上前缀限定符,避免二义性最好的办法是在派生类中为该成员定义一个新的版本。

3、多重继承demo:

#include <iostream>  
#include <string>  
using namespace std;  
class Worker
{
public:
    Worker(string code = "wk")
    {
        m_strCode = code;
        cout << "Worker()" << endl;
    }
    virtual ~Worker()
    {
        cout << "~Worker()" << endl;
    }
    void carry()
    {
        cout << m_strCode << endl;
        cout << "Worker-carry()" << endl;
    }
protected:
    string m_strCode;
};

class Farmer
{
public:
    Farmer(string name = "fa")
    {
        m_strName = name;
        cout << "Farmer()" << endl;
    }
    virtual ~Farmer()
    {
        cout << "~Farmer()" << endl;
    }
    void sow()
    {
        cout << m_strName << endl;
        cout << "Farmer-sow()" << endl;
    }
protected:
    string m_strName;
    
};

class MigrantWorker  : public Farmer, public Worker//构造函数执行的顺序和声明的顺序一致。
{
public:
    MigrantWorker(string name, string code): Worker(code), Farmer(name)//列表初始化,向下构造。
    {
        cout << "MigrantWorker" << endl;
    }
    ~MigrantWorker()//向上析构。
    {
        cout << "~MigrantWorker()" << endl;
    }
    
};

int main(int argc, char const *argv[])
{
    MigrantWorker *p = new MigrantWorker("jack","100");
    p->carry();
    p->sow();
    delete p;
    p =  nullptr;
    return 0;
}

继承与接口_虚继承_02

4、虚继承

虚继承的目的是令某个类做出声明,承诺愿意共享它的基类,共享的基类子对象称为及虚基类,在此情况下,无论虚基类在集成体系中出现多少次,派生类中都只包含唯一一个共享的虚基类对象

虚继承主要解决的是菱形继承问题。对于菱形继承,使用虚继承的好处在于避免重复拷贝最上层的父类

【Note】:
1)虚派生只影响从指定了虚基类的派生类中进一步派生出的类,它不会影响派生类本身。
2)虚基类总是先于非虚基类构造,与它们在继承体系中的次序和位置无关。
  只要我们能创建虚基类的派生类对象,该派生类的构造函数就必须初始化它的虚基类。
  首先用最底层派生类的构造函数的初始值初始化该对象的虚基类子部分,虚基类优先构造,析构函数执行顺序与构造函数相反。

5、虚继承demo:

#include <iostream>  
#include <string>  
using namespace std;  
//对于菱形继承,使用虚继承的好处在于避免重复拷贝最上层的父类。
class Person
{
public:
    Person(string color = "blue")
    {
        m_strColor = color;
        cout << "Person()" << endl;
    }
    virtual ~Person()
    {
        cout << "~Person()" << endl;
    }
    void printColor()
    {
        cout << m_strColor << endl;
        cout << "Person-printColor()" << endl;
    }
protected:
    string m_strColor;
};

class Worker : virtual public Person//虚继承。
{
public:
    Worker(string code = "wk", string color = "blue") : Person(color)
    {
        m_strCode = code;
        cout << "Worker()" << endl;
    }
    virtual ~Worker()
    {
        cout << "~Worker()" << endl;
    }
protected:
    string m_strCode;
};

class Farmer : virtual public Person//虚继承。
{
public:
    Farmer(string name = "fa", string color = "blue") : Person(color)
    {
        m_strName = name;
        cout << "Farmer()" << endl;
    }
    virtual ~Farmer()
    {
        cout << "~Farmer()" << endl;
    }
protected:
    string m_strName;
    
};

class MigrantWorker  : public Farmer, public Worker
{
public:
    MigrantWorker(string name, string code, string color): 
                  Worker(code, color), Farmer(name, color)
    {
        cout << "MigrantWorker" << endl;
    }
    ~MigrantWorker()
    {
        cout << "~MigrantWorker()" << endl;
    }
    
};

int main(int argc, char const *argv[])
{
    MigrantWorker *p = new MigrantWorker("jack","100", "yellow");
    p->Farmer::printColor();//使用前缀限定符避免发生二义性。
    p->Worker::printColor();
    delete p;
    p =  nullptr;
    return 0;
}

继承与接口_虚基类_03

四、纯虚函数和抽象类

抽象基类是把某一些具有相似特征的类抽象化,形成一个新的类,比如人。当多个类之间有相似的方法和数据成员时,可以定义一个抽象基类。

含有(未经覆盖直接继承)纯虚函数的类是抽象基类,将虚函数后面加上“=0”即为纯虚函数

继承与接口_虚继承_04

1、面试题—>纯虚函数的实现原理,为什么抽象基类不能被实例化?

继承与接口_继承_05


  所有的虚函数都会被加入到虚函数表中,而纯虚函数在虚函数表中对应的vptr是空,也就是指向一个不存在的函数,而编译器不允许有调用一个不存在的函数。

2、面试题—>如何阻止一个类被实例化?

使用抽象基类或者将构造函数定义为private。

五、运算符重载与四种类型转换

1、运算符重载

Integer operator+(int value, Integer integer) {
    int tmpValue = integer.m_value + value;
    return Integer(tmpValue);
}

2、四种类型转换

C++的四种强制类型转换,所以C++不是类型安全的。分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast。

// static_cast用于替换C语言中的强制类型转换
static_cast<type-id> (expression)

// 将基类指针转换为派生类指针
dynamic_cast<type-id> (expression)

// 转化任何内置的数据类型为其他任何的数据类型
reinpreter_cast(expression)

// 把非const类型转换为const类型,或者去掉const属性
const_cast(expression)


标签:类型转换,函数,继承,基类,接口,派生类,构造函数
From: https://blog.51cto.com/u_6526235/7274774

相关文章

  • 如何把一个接口设计好? | 京东云技术团队
    如何设计一个接口?是在我们日常开发或者面试时经常问及的一个话题。很多人觉得这不就是CRUD,能实现不就行了。单纯实现来说,并非难事,但要做到易用、易扩展、易维护并不是一件简单的事。这里并不强调一些个接口设计的原则或者设计方法,仅从如何设计一个好的接口出发,简单讨论。1、命名规......
  • 如何把一个接口设计好?
    如何设计一个接口?是在我们日常开发或者面试时经常问及的一个话题。很多人觉得这不就是CRUD,能实现不就行了。单纯实现来说,并非难事,但要做到易用、易扩展、易维护并不是一件简单的事。这里并不强调一些个接口设计的原则或者设计方法,仅从如何设计一个好的接口出发,简单讨论。1、命名......
  • 接口查询性能优化-缓存
    查询性能优化缓存种类mybatis一级缓存mybatis二级缓存本地缓存各个节点的数据不同步分布式缓存redis前端h5的缓存本地缓存session缓存mybatis一级缓存一个方法中对同一个sql,查询了多次当在这个方法上加@transactional后续的查......
  • 类和对象(继承)
    继承是面向对象三大特性之一继承的好处:减少重复代码语法:class 子类:继承方式  父类子类也称派生类父类也称基类比如:classA:publicBA类称为子类(派生类)B类称为父类(基类)public叫做继承方式派生类中的成员,包含两大部分一类是从基类继承过来的,一类是自己增加的成员。......
  • 使用autofac注册继承特定接口的类或接口
    publicclassMyModule:Module{///<summary>//////</summary>///<paramname="builder"></param>protectedoverridevoidLoad(ContainerBuilderbuilder){//扫描程序集中所有继承自ITransientDepend......
  • Qt开发思想探幽]QObject、模板继承和多继承
    @目录[Qt开发探幽]QObject、模板继承和多继承1.QObject为什么不允许模板继承:2.如果需要使用QObject进行多继承的话,子对象引用的父类链至多只能含有一个QObject3.如果使用模板类和QObject做多继承,编译不通过问题场景[Qt开发探幽]QObject、模板继承和多继承当我们在用Qt开发一个......
  • python+playwright 学习-77 playwright 发送接口请求APIRequestContext
    前言每个Playwright浏览器上下文都有与其关联的APIRequestContext实例,该实例与浏览器上下文共享cookie存储,可以通过browser_context.request或page.request访问。也可以通过调用api_request.new_context()手动创建一个新的APIRequest上下文实例。通过浏览器发请求可以通过browser......
  • 如何调用api接口获取到商品数据
    要调用API接口获取商品数据,需要进行以下步骤:确定API接口首先需要确定要使用的API接口,可以通过搜索引擎或者相关文档来查找适合的API接口。以淘宝开放平台为例,可以使用淘宝的商品信息查询API接口来获取商品数据。注册API账号并获取API密钥要使用API接口,需要先在API平台上注册一个账......
  • 函数式接口和方法引用
    函数式接口和方法引用1.函数式接口概述只有一个抽象方法(default不算)的接口称为函数式接口.通常有注解:@FunctionalInterface进行标识.2.方法引用只有在lambda表达式总发现方法体只有一行代码就可以简化写法;例如:lambda的三层简化写法newArrayList<String>().st......
  • 电商数据接口API:品牌价格监控与数据分析的重要工具
    一、引言随着电子商务的快速发展,传统品牌企业越来越重视在线销售市场。为了在竞争激烈的市场环境中取得成功,企业需要实时掌握市场动态,了解自身产品的销售情况、价格趋势以及竞品信息。为了实现这一目标,各大电商平台(如淘宝、京东和拼多多)纷纷开放其数据接口,形成了电商数据接口API。......