c ++虚拟类:有趣的一点

时间:2012-10-02 18:05:49

标签: c++ polymorphism virtual virtual-inheritance

请告诉我为什么以下程序的输出如下。我没有在c ++中获得虚拟类。请遵守以下代码:

class B
{
public:
    B(char c = 'a') : m_c(c) {}

public:
    char get_c() const { return m_c; }
    void set_c(char c) { m_c = c; }

private:
    char m_c;
};

class C: public B
{ };

class D: public B
{ };

class E
    : public C
    , public D
{ };

int main()
{
    E e;
    C &c = e;
    D &d = e;
    std::cout << c.get_c();
    d.set_c('b');
    std::cout << c.get_c() << std::endl;
    return 0;
}

O / P:aa 我希望输出为ab。得到“aa”的原因是什么?

如果我有c.set_c('b')而不是d.set_c('b')那么我会得到O / P:“ab”,这里也是,我不知道为什么会这样。 c,d都只指一个对象。

class C:virtual public B{};
class D:virtual public B{};

如果C类,D类几乎从B继承,那么 O / P永远是“ab”

3 个答案:

答案 0 :(得分:9)

B中有两份E,一份来自C,另一份来自D。当您致电d.set_c('b')时,您正在修改m_c D中的B。当您致电c.get_c()时,您会在m_c C中获得B,而C尚未更改。

当您DB虚拟地从B继承时,它会解决问题,因为E只有{{1}}的一个副本1}}。

这是相关的:http://www.parashift.com/c++-faq/virtual-inheritance-where.html

答案 1 :(得分:1)

我不确定我是否理解这个问题,但你的问题包含了答案,将B声明为C和D的虚拟基础并且你得到了。

#include <iostream>

class B
{
public:
    B(char c = 'a') : m_c(c) {}

public:
    char get_c() const { return m_c; }
    void set_c(char c) { m_c = c; }

private:
    char m_c;
};

// note virtual inheritance
class C: virtual public B
{ };

// note virtual inheritance
class D: virtual public B
{ };

class E
: public C
, public D
{ };

int main()
{
    E e;
    C &c = e;
    D &d = e;
    std::cout << c.get_c() << std::endl;;
    d.set_c('d');
    std::cout << c.get_c() << std::endl;
    c.set_c('c');
    std::cout << d.get_c() << std::endl;
    return 0;
}

导致你想要的输出,不是吗?

a
d
c

答案 2 :(得分:1)

考虑class C : public BC* c = new C,然后c指向以B开头的存储,因为C*也是B*。对于true,这是class D : public B

现在适用于class E : public C, public DE* e = new E()e的记忆就像:

{| B of C | other members of C }{| B of D | other members of D}

正如您在上面的案例中所见,我们有B的一个C实例和D的另一个实例,现在很明显当你只调用((D*)e)->set_c( 'b' )时更改B的{​​{1}}实例和D B实例将保持不变。

现在,当您说C时,C ++与class C : public virtual B实际上从B继承的其他类共享B个实例。所以在这种情况下e类似于:

           | shared B |
    | C members | | D members |

正如您所看到的,我们只有一个B,因此调用((C*)e)->set_c((D*)e)->set_c将同时B