Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在派生类中继承和使用成员变量的模式,而无需每次转换

在派生类中继承和使用成员变量的模式,而无需每次转换
EN

Stack Overflow用户
提问于 2022-03-02 21:50:43
回答 3查看 135关注 0票数 0

我有一个基类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Base{
protected:
    Storage* _storage;

    virtual void createStorage(){
        delete storage;
        _storage = new Storage();
    }

    void exampleUseOfBaseStorage(){
        _storage->baseData++; //some complex calculation
    }
}

struct Storage{
    int baseData;
}

每个派生类都有自己的存储类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct DerivedStorage : Storage{
    int derivedData;
}

在派生类中,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Derived{
protected:
    virtual void createStorage() override{
        delete storage;
        _storage = new DerivedStorage();
    }
}

因此,_storage可以用于所有基类成员和派生类成员。缺点是,因为对于每个派生类,我必须将存储类型转换为DerivedStorage,或者派生类使用的任何类型的存储,所以每次输入cast语句都非常繁琐。有一个优雅的方法绕过它吗?

我的解决方案是只有一个类型为DerivedStorage的变量,只需在派生类成员函数中使用。例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Derived{
protected:
    DerivedStorage* _ds = nullptr;

    virtual void createStorage() override{
        delete storage;
        _storage = new DerivedStorage();
        _ds = _storage; // Use _ds in all member functions of Derived instead of _storage
    }

    void exampleUseOfDerivedStorage(){
         _ds->derivedData++; //some complex calculation
    }
}

是否有更优雅的模式可用于此用例?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-03-03 02:28:37

我认为问题应该是:“你真的需要储存出来吗?”大多数时间组合/聚合应该足够了。

即使需要计算派生存储和基存储中的数据,也可以在派生类中访问它们。

构图示例

现场演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>

struct Storage{
    int baseData{};
};
struct DerivedStorage{
    int derivedData{};
};

class Base{
public:
    Storage _storage;

    void exampleUseOfBaseStorage(){
        _storage.baseData++; //some complex calculation
    }
};

class Derived: Base{
public:
    DerivedStorage _ds;

    void exampleUseOfDerivedStorage(){
        _ds.derivedData++; //some complex calculation
        std::cout << "baseData: " << _storage.baseData << std::endl;
        std::cout << "derivedData: " << _ds.derivedData << std::endl;
    }
};

int main(){
    Derived d;
    d.exampleUseOfDerivedStorage();
    
    return 0;
}

CRTP示例

下面的示例详细介绍了user17732522关于CRTP使用的回答

现场演示

我将所有成员更改为public,因为示例没有详细说明何时调用createStorage()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>

struct Storage{
    int baseData{};
};
struct DerivedStorage : Storage{
    int derivedData{};
};

template<typename DS>
class Base{
public:
    Storage* _storage;

    virtual void createStorage(){
        delete _storage;
        _storage = new Storage();
    }

    DS* getStorage(){
        return static_cast<DS*>(_storage);
    }

    void exampleUseOfBaseStorage(){
        _storage->baseData++; //some complex calculation
    }
};

class Derived: Base<DerivedStorage>{
public:

    virtual void createStorage() override{
        delete _storage;
        _storage = new DerivedStorage();
    }

    void exampleUseOfDerivedStorage(){
        getStorage()->derivedData++; //some complex calculation
        std::cout << "derivedData: " << getStorage()->derivedData << std::endl;
    }
};

int main(){
    Derived d;
    d.createStorage();
    d.exampleUseOfDerivedStorage();
    
    return 0;
}
票数 1
EN

Stack Overflow用户

发布于 2022-03-03 00:44:35

我会将转换放入成员函数中,而不是使用数据成员。成员函数可以在每个派生类中具有相同的名称。如果您真的不想在每个派生类中键入函数定义,可以使用CRTP来实现它。

使用数据成员使得无法安全地使用对特殊成员函数的零规则方法,您必须在每个派生类中显式地实现它们。

我假设显示的代码只是缩写,但是基类也有同样的问题。如果它使用的是std::unique_ptr<Storage>而不是原始指针,那么它可以简单地遵循零的规则,而不必费心地实现任何特殊的成员函数,但是当它写在问题中时,需要显式地定义特殊的成员函数,以避免在类被复制/移动时导致UB。(此外,std::unique_ptr还将使createStorage异常安全,而目前并非如此。)

票数 2
EN

Stack Overflow用户

发布于 2022-03-03 00:20:38

由于方法Base::exampleUseOfBaseStorage是受保护的,因此该方法的调用方仅限于派生类(和基)。

因此,如果每个派生类都将每个存储作为自己的成员,则可以将其用作Base::exampleUseOfBaseStorage的参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Base{
protected:
    //(This will be called from Drived)
    void exampleUseOfBaseStorage( Storage *storage );
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71332646

复制
相关文章
【16】万恶的引导设计:配表篇
上一篇,我们了解了引导的一些理论知识,包括分段、分步的概念,强引导与弱引导,引导的触发、类别、操作、保存点等,本篇笔者将结合这些理论来聊聊引导的配表。
代码咖啡
2019/10/08
1K0
压测grafana面板之请求响应耗时解析
在某次压测护航中,有同学提问,为什么被压测服务后台日志查看到的大部分请求耗时都比95分位平均响应时间小?是不是数据统计的有问题?
cailynyu
2022/02/14
2.9K1
一个MySQL建表需求的讨论和引导
昨天收到一个业务同学的需求邮件,一般有些复杂的需求业务同学会发邮件告知我们,需要我们评估之后再做交付,我看了邮件之后,发现这个需求好像有点别扭,大体的意思是在中间件的环境中创建一张表,表结构如下:
jeanron100
2021/03/16
2.8K0
Bootstrap响应式前端框架笔记十五——面板与井
    Bootstrap中的面板由pannel相关类来创建,一个完整的面板分为面板头部、面板体和面板注脚,并且Bootstrap中默认定义了一些面板风格,示例如下:
珲少
2018/08/15
8000
Bootstrap响应式前端框架笔记十五——面板与井
【嘘】内有惊喜,请勿扩散
▼扫码加入DNSPod官方用户群▼ 第一时间追踪活动最新动态 SMB 腾讯云中小企业产品中心     腾讯云中小企业产品中心(简称SMB),作为腾讯云体系中唯一专业服务于8000万中小企业的业务线,致力于为中小微企业提供全面完善贴心的数字化解决方案。产品线覆盖了企业客户从创业起步期、规范治理期、规模化增长期、战略升级期等全生命周期,针对性的解决企业的信息化、数字化、智能化的生产力升级需求。本中心还拥有两大独立腾讯子品牌:DNSPod与Discuz!,在过去15年间,为超过500万企业级客户提供了强大、优质
腾讯云DNSPod团队
2022/01/21
2610
苦逼的程序员(内有惊喜)
很多人拿程序员来开涮,比如: 从前,有一个程序员,他临死的时候, 不小心得到了一盏神灯 。然后他向神灯许愿, 希望在有生之年能写一个好项目。 后来,后来他得到了永生。 再比如: 程序员职业服装! 还
用户1631416
2018/04/12
6030
苦逼的程序员(内有惊喜)
动手练一练,做一个响应式的后台管理面板
作为一名前端开发者,我们或多或少都会接触后台管理系统的制作,你是否会亲自纯手工制作做还是从网上找源码改一个呢?今天我们将从零开始纯手工制作一个后台管理面板的首页,通过这个案例你将会学习到如何制作一个响
前端达人
2020/03/16
1.3K0
动手练一练,做一个响应式的后台管理面板
千万级数据表选错索引导致的线上慢查询事故
又和大家见面了!又两周过去了,我的云笔记里又多了几篇写了一半的文章草稿。有的是因为质量没有达到预期还准备再加点内容,有的则完全是一个灵感而已,内容完全木有。羡慕很多大佬们,一周能产出五六篇文章,给我两个肝我都不够。好了,不多说废话了...
Rude3Knife的公众号
2020/08/02
1.4K0
国内有哪些好的刷题网站?
CoderAfterWork靠写代码挣钱去浪... 刷题也就这么点地方 1、Leetcode 鼎鼎大名的Leetcode,据不完全统计在上面被刷过的题可以围绕地球三圈。(没说赤道哈,就是这么严谨。)总之,很多国内外的码农在上面刷题。难度从easy到hard都有,而且覆盖面极广。现在还增加了数据库和shell,相匹配的论坛也可以多看看。很锻炼和国外码农沟通的能力,对于以后去混Github也有好处。 特点:各种语言支持很广泛,题型覆盖很广,测试数据集较弱。 2、Codility 同样一家著名的国外刷题网站。和L
前朝楚水
2018/04/04
3.4K0
Grafana 统计面板与文本面板的使用
统计面板可以用于显示一个大的统计值和一个可选的背景颜色,我们可以使用阈值来控制背景或颜色值,效果如下所示:
我是阳明
2021/11/23
2.6K0
MongoDB 路由表刷新导致响应慢场景解读
MongoDB sharding 实例从3.4版本升级到 4.0版本 以后插入性能明显降低,观察日志发现大量的 insert 请求慢日志:
MongoDB中文社区
2020/11/11
2K0
MongoDB 路由表刷新导致响应慢场景解读
2018,新年快乐 | 内有福利
长按二维码关注 “腾讯乐享” 随机送出20个QQ公仔 福利
腾讯乐享
2019/03/12
1.3K0
2018,新年快乐 | 内有福利
面板环境的安装
安装完成在浏览上打开面板的地址,登入面板,面板会自动推荐你安装环境套件,这里有两种选择,第一种是LNMP套件,第二种是LAMP套件:
霹格软件
2018/09/11
6540
面板环境的安装
cPanel面板和宝塔面板区别
  cPanel面板和宝塔面板有什么区别?cPanel面板和宝塔面板都是一种目前比较常用的服务器管理面板,那么,cPanel面板和宝塔面板哪个好呢?让我们一起来详细了解一下cPanel面板和宝塔面板吧
会长君
2023/04/26
4.2K0
清除linux系统的多余引导
由于我把系统给升级(update)了,在grub引导模式出现新旧版本(Grub与Grub2)的引导系统分别为正常启动和进入恢复模式各2个引导项,如下图显示:百度找不到相关或类似的教程,只好半夜起来研究,现在做好了并写下笔记。
用户1685462
2021/07/23
6.3K0
利用threshold实现的遮罩引导
点击“开始引导”,则进入引导操作。除指定的按钮可以操作外,其它区域均不可点击。这种应用当新功能或是新产品上线后,用来引导用户来使用产品/功能,是十分有用的。facebook也有类似的引导,方法也很简单:用4个绝对定位的DIV(指定一个背景 + 一定透明度)遮住其它部分,这样可以被操作的区域就“留空”出来。
meteoric
2018/11/16
6160
Netty中的引导类Bootstrap
Bootstrap是用来组织Netty的各个结构(pipeline,handler,eventloop),并使他们运行起来的类结构。分成两块,一个是客户端引导类Bootstrap,只用1个channel来处理所有的网络交互,另一个是服务端的ServerBootstrap,它提供一个父channel来接受客户端的请求,然后父channel创建多个子channel来用于的通信
爬蜥
2019/07/09
9560
旁观者.个性引导页个性引导页
这款个人主页简约而不失优雅,背景图片为随机api,共有38张随机图片,每次刷新都会看到不一样的美图。
小化先森
2023/03/05
1.1K0
点击加载更多

相似问题

这个单元测试是否与实现紧密耦合?

30

逻辑与数据紧密耦合的单元测试系统

40

不耦合到实现细节的单元测试行为

20

共享数据库与紧耦合消息模型

10

如何将此耦合应用程序解耦?

40
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文