子类

时间:2015-04-27 01:18:50

标签: c++

我有一个A类,我为其定义了一个(重载)流插入运算符。我公开从这个A类派生出一个B类,它有一个额外的数据成员。因此,我需要重新定义派生类的重载流插入运算符,我这样做:

#include <iostream>

using namespace std;

class A {
    int i;
    char c;
public:
    A(int i = 0, char c = ' ') {
        this->i = i;
        this->c = c;
    }
    friend ostream& operator << (ostream&, const A&);
};

class B : public A {
    double d;
public:
    B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
    friend ostream& operator << (ostream&, const B&);
};

ostream& operator << (ostream& out, const A& a) {
    out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
    return out;
}

ostream& operator << (ostream& out, const B& b) {
    out << b;
    out << "\nDouble: " << b.d << endl;
    return out;
}

int main() {
    A a(10, 'x');
    B b(20, 'y', 5.23);
    cout << b;

    return 0;
}
  

问题1:这是一种合适的技巧吗?如果没有,请让我知道我哪里出错。

     

问题2:运行时,此程序崩溃。为什么这样?

2 个答案:

答案 0 :(得分:2)

支持此操作的一种常见方法是让重载的运算符调用虚拟成员函数:

class A { 
public:
    virtual std::ostream &write(std::ostream &os) const { 
        // write self to os
        os << "A\n";
        return os;
    }
};

class B : public A { 
public:
    virtual std::ostream &write(std::ostream &os) const { 
        // write self to os
        // This can use the base class writer like:
        A::write(os);
        os << "B\n";
        return os;
    }
};

然后运算符重载只调用该成员函数:

std::ostream &operator<<(std::ostream &os, A const &a) {
    return a.write(os);
}

由于write是虚拟的,并且您正在通过(const)引用传递A,因此会根据实际类型调用正确的成员函数(即A::write if该对象实际上是A的实例,如果它是B::write的实例,则为B

例如,我们可以运用这样的东西:

int main() { 
    A a;
    B b;

    std::cout << a << "\n";
    std::cout << b << "\n";
}

...产生这样的输出:

A

A
B

在实际使用中,您可能希望保护write个功能,并使operator<<成为A的朋友。

答案 1 :(得分:0)

程序崩溃是因为你的第二个插入操作符自行调用:

print(ostream&) const

通常这是一个很好的方法,虽然我更喜欢给类一个公共虚拟{{1}}函数,并让插入操作符调用它。