C ++协方差意外行为

时间:2014-01-21 15:13:15

标签: c++ inheritance covariance

我得到了一个意想不到的结果,到目前为止我无法解释。

虽然生成了同一个类BASIC2(继承自BASIC1)的对象两次,但在生成的对象上使用朋友operator<<时会生成不同的消息。

见下面的代码

我让D(继承自Derived的类Base的对象)生成类BASIC2的对象,并将其称为朋友operator<<。这会产生预期的消息"BASIC2 object"

我让B生成类BASIC1的对象并调用其朋友operator<<。这会按照我的预期输出"BASIC1 object"

然后我使用虚拟继承让B2Base* B2 = &D;)生成BASIC2的对象。我遵循调试器中的代码流(Visual Studio 2010),这正确地生成了BASIC2的对象。但是,朋友operator<<未在BASIC2对象上调用,而是使用来自班级operator<<的朋友BASIC1(因此输出"BASIC1 object")。

另请注意,我希望BASIC2继承BASIC1,因为我想利用协方差行为。

int main(int argc, char* argv[]) {
    Base B;
    Derived D;
    Base* B2 = &D;
    std::cout << *D.generate(0) << std::endl;
    std::cout << *B.generate(0) << std::endl;
    std::cout << *(B2->generate(0)) << std::endl;
    system("pause");
}

输出结果为:

BASIC2 object
BASIC1 object
BASIC1 object
class BASIC1 {
public:
    friend std::ostream& operator<<(std::ostream& os, const BASIC1& basic) {
    os << "BASIC1 object";
    return os;
    }
};

class BASIC2 : public BASIC1 {
    friend std::ostream& operator<<(std::ostream& os, const BASIC2& basic) {
    os << "BASIC2 object";
    return os;
    }
};

class Base {
public:
    virtual BASIC1* generate(double num) const {
    return new BASIC1();
    }
protected:
private:
};

class Derived : public Base {
public:
    virtual BASIC2* generate(double num) const override {
    return new BASIC2();
    }
protected:
private:
};

2 个答案:

答案 0 :(得分:5)

选择运算符&lt;&lt;基于编译时已知的对象的静态类型。为了达到你想要的目的,不要定义两个运算符&lt;&lt;函数,但仅在BASIC1中有一个:

    friend std::ostream& operator<<(std::ostream& os, const BASIC1& basic) {
      Write(os);
      return os;
    }

并定义虚函数在BASIC1和BASIC2中写入以执行所需操作:

virtual void Write(std::ostream& os) const {
   os << "BASIC1 object";
}

答案 1 :(得分:1)

谢谢!对我来说,我的问题的最终结论是:如果你通过动态调度生成对象的对象上调用友元运算符&lt;&lt;(std :: ostream&amp; os,const Base&amp; object)。您需要在运算符中使用虚函数&lt;&lt;允许动态调度运算符&lt;&lt;