首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C类继承B类,A类B类也继承A类

C类继承B类,A类B类也继承A类
EN

Stack Overflow用户
提问于 2014-03-13 14:50:15
回答 2查看 3.4K关注 0票数 3

我想记录来自基类B和派生类C的消息,对于哪个类记录了消息是不同的:

代码语言:javascript
复制
#include "iostream"

class Logger {
public:
    Logger(std::string name) : name_(name) {}
    void log(std::string msg) { std::cout << name_ << ": " << msg << std::endl; }
private:
    std::string name_;
};

class B : public Logger {
public:
    B() : Logger("Class B" ) {}
    void doSomethingInB() {
        log("B doing something");
    }
};

class C : public B, public Logger {
public:
    C() : Logger("Class C" ) {}
    void doSomethingInC() {
        log("C doing something");
    }
};

int main() {
    B* b = new B();
    C* c = new C();

    b->doSomethingInB(); // I want this to output: Class B: B doing something

    c->doSomethingInC();
    c->doSomethingInB(); // I also want this to output: Class B: B doing something

    return 0;
}

我得到的错误“在‘C’中由于默认启用歧义而无法访问直接基‘Logger’,这是不言自明的。

我能实现什么不同的模型来完成这个任务呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-03-13 15:12:17

您可以使用虚拟继承,如inheritance的答案中所示,但这只会使C实例中只有一个C对象,其副作用是日志将无法输出正确的名称(您还在这个答案的注释中发现了这个问题)。

作文

一种解决方案是使用组合而不是继承:

代码语言:javascript
复制
class B
{
private:
    Logger log;
// ...
};

可能是最简单的解决办法。你可以看到一个live example here

继承

另一种解决方案是通过使用CRTP使基类有所不同。这就是:

代码语言:javascript
复制
template<typename T>
class LoggerImp : public Logger
{
public:
    LoggerImp(const std::string& n) : Logger(n) {}
};

class B : private LoggerImp<B>
{
private:
    typedef LoggerImp<B> LL;

public:
    B() : LoggerImp<B>("Class B" ) {}

    void doSomethingInB()
    {
        LL::log("B doing something");
    }
};

class C : public B, private LoggerImp<C>
{
private:
    typedef LoggerImp<C> LL;

public:
    C() : LoggerImp<C>("Class C" ) {}

    void doSomethingInC()
    {
        LL::log("C doing something");
    }
};

一些注意事项:

  • 我使用私有继承,因为据我所知,记录器只对BC有用,而对这些对象的所有者没有用处。
  • CRTP用于消除基名的歧义。这还不够,但对你的问题有很大帮助。
  • 类型胡枝子是为了可读性。记录器基有不同的名称这一事实允许正确地对它们进行类型划分,从而允许我们调用正确的日志函数。
  • 派生类中的ty清晰度隐藏在基类中(前提是它们是同名的)。因此,您可以使用相同的代码在不同的类中登录。
  • 您还可以直接使Logger类成为CRTP。
  • 你可以看到a live example here
票数 1
EN

Stack Overflow用户

发布于 2014-03-13 14:54:11

编辑:响应c->doSomethingInB();需要打印Class B: B doing something的要求,考虑组合而不是继承,因为您需要B作为自己的子类,它的记录器实际上与C的不一样(除非这里有更多的需求)。示例:

代码语言:javascript
复制
class Logger {
public:
    Logger(std::string name) : name_(name) {}
    void log(std::string msg) { std::cout << name_ << ": " << msg << std::endl; }
private:
    std::string name_;
};

class B {
public:
    B() : logger_("Class B" ) {}
    void doSomethingInB() {
        logger_.log("B doing something");
    }
private:
  Logger logger_;
};

class C : public B {
public:
    C() : logger_("Class C" ) {}
    void doSomethingInC() {
        logger_.log("C doing something");
    }
private:
  Logger logger_;
};
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22382351

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档