为什么这个C ++继承代码示例的行为类似

时间:2018-04-10 21:10:28

标签: c++ inheritance virtual function-overriding

我有一个代码示例,对我来说很奇怪。 使用C ++中的继承,可以使用纯虚函数(也称为Interface)声明指向基类的指针数组,并在其上调用派生成员函数;

class Base {

public:

    virtual void call() = 0;

};

class Derived1 : public Base {

public:

    void call() override final {

        std::wcout << L"derived 1" << std::endl;

    }

};

class Derived2 : public Base {

public:

    void call() override final {

        std::wcout << L"derived 2" << std::endl;

    }

};

int main() {

    Base* b[2];    

    b[0] = new Derived1;
    b[1] = new Derived2;

    for (int i = 0; i < 2; ++i) {

        b[i]->call();

    }

    return 0;

}

给出了:

derived 1
derived 2

按计划进行。 但是当我尝试使用代码示例时,这让我有点困惑:

class Base {

public:

    virtual Base* print() = 0;

    template<typename T>
    Base& operator<<(const T &_val) {

        std::wcout << L" d0 << " << _val;
        return *this;

    }

};

class Derived1 : public Base {

public:

    Derived1* print() override final {

        return this;

    }

    template<typename T>
    Derived1& operator<<(const T &_val) {

        std::wcout << L" d1 << " << _val;
        return *this;

    }

};

class Derived2 : public Base {

public:

    Derived2* print() override final {

        return this;

    }

    template<typename T>
    Derived2& operator<<(const T &_val) {

        std::wcout << L" d2 << " << _val;
        return *this;

    }

};

int main() {

    Base* b[2];

    b[0] = new Derived1;
    b[1] = new Derived2;

    for (int i = 0; i < 2; ++i) {

        std::wcout << typeid(*b[i]->print()).name();
        *b[i]->print() << 7 << 7;
        std::wcout << std::endl;

    }

    return 0;

}

输出结果为:

8Derived1 d0 << 7 d0 << 7
8Derived2 d0 << 7 d0 << 7

这意味着只调用 Base的运算符&lt;&lt; (但print()返回类型似乎是正确的。)

问题是为什么它的行为如此

UPD:

似乎我需要静态多态,这里没有虚函数。但这怎么可能实现呢? 我需要一组不同的Derived类来在operator&lt;&lt;&lt;&lt;在任何数据类型上。 UPD2:

看起来我可以将类型擦除用于运算符&lt;&lt;参数。但是如何在derived的运算符中恢复类型&lt;&lt;然后? (例如,如果我建议使用boost :: any)

1 个答案:

答案 0 :(得分:2)

您的operator << ()不是虚拟的,因此,如果您调用此基类指针的运算符,则始终会调用基类实现。

这是因为它是一种模板方法,模板方法不能virtual(参见Can a C++ class member function template be virtual?)。

解决方案是为每种受支持的数据类型编写虚拟专用operator << ()(如果您真的希望它们在继承的类之间有所不同)。

这是更改后的代码:

class Base {

public:

    virtual Base* print() = 0;

    virtual Base& operator<<( int _val ) = 0;

};

class Derived1 : public Base {

public:

    Derived1* print() override final {

        return this;

    }

    Base& operator<<( int _val ) override final {

        std::wcout << L" d1 << " << _val;
        return *this;

    }

};

class Derived2 : public Base {

public:

    Derived2* print() override final {

        return this;

    }

    Base& operator<<( int _val ) override final {

        std::wcout << L" d2 << " << _val;
        return *this;

    }

};

int main() {

    Base* b[2];

    b[0] = new Derived1;
    b[1] = new Derived2;

    for (int i = 0; i < 2; ++i) {

        std::wcout << typeid(*b[i]->print()).name();
        *b[i]->print() << 7 << 7;
        std::wcout << std::endl;

    }

    return 0;

}

另一种方法是,仅通过类层次结构(此处为:类名)实现不同的部分,并使用模板运算符进行泛型调用。

#include <iostream>
#include <string>

class Base {

public:

    virtual Base* print() = 0;
    virtual const wchar_t* className() const = 0;

    template<typename T>
    Base& operator<<(const T &_val) {

        std::wcout << L" " << className() << L" << " << L" << " << _val;
        return *this;

    }

};

class Derived1 : public Base {

public:
    const wchar_t* className() const override final { return L"d1"; }

    Derived1* print() override final {

        return this;

    }

};

class Derived2 : public Base {

public:
    const wchar_t* className() const override final { return L"d2"; }

    Derived2* print() override final {

        return this;

    }

};

int main() {

    Base* b[2];

    b[0] = new Derived1;
    b[1] = new Derived2;

    for (int i = 0; i < 2; ++i) {

        std::wcout << typeid(*b[i]->print()).name();
        *b[i]->print() << 7 << 7;
        std::wcout << std::endl;

    }

    return 0;

}

最后一种方法是根据类类型进行RTTI转换,并根据类类型调用专用的operator << ()

#include <iostream>

class Derived1;
class Derived2;

class Base {

public:

    virtual Base* print() = 0;


};

class Derived1 : public Base {

public:

    Derived1* print() override final {

        return this;

    }

    template<typename T>
    Derived1& operator<<(const T &_val) {

        std::wcout << L" d1 << " << _val;
        return *this;

    }

};

class Derived2 : public Base {

public:

    Derived2* print() override final {

        return this;

    }

    template<typename T>
    Derived2& operator<<(const T &_val) {

        std::wcout << L" d2 << " << _val;
        return *this;

    }

};

template<typename T>
Base& operator<<( Base& _base, const T &_val) {

    if( typeid( _base ) == typeid( Derived1 ))
        return dynamic_cast<Derived1*>(&_base)->operator << (_val);
    else
        return dynamic_cast<Derived2*>(&_base)->operator << (_val);
}

int main() {

    Base* b[2];

    b[0] = new Derived1;
    b[1] = new Derived2;

    for (int i = 0; i < 2; ++i) {

        std::wcout << typeid(*b[i]->print()).name();
        *b[i]->print() << 7 << 7;
        std::wcout << std::endl;

    }

    return 0;

}