C++;继承运算符'<<';关于模板类 我有下面的C++代码,这说明了我的问题。 我的目标是重写继承类中的stream操作符,以便根据对象类型打印特定流: #include <iostream> #include <unordered_set> using namespace std; template <typename T> class Base { public: Base(){} Base(T n): value_(n){} friend inline ostream &operator<<(ostream &os, const Base &b) { b.to_str(os); return os; } protected: T value_; // All object should implement this function virtual void to_str(ostream& os) const { os << value_; } }; template <typename T> class Child: public Base<T> { public: Child(T n): Base<T>(n){} protected: void to_str(ostream& os) const override { os << "{"; for (auto v = this->value_.begin(); v != this->value_.end(); v++) { if(v != this->value_.begin()) os << ","; os << (*v); } os << "}"; } }; int main() { Base<string> b("base"); Child<unordered_set<string>> c({"child"}); cout << "b: " << b << endl; cout << "c: " << c << endl; return 0; } #包括 #包括 使用名称空间std; 模板 阶级基础{ 公众: Base(){} 基(tn):值_un{} friend inline ostream&operator

C++;继承运算符'<<';关于模板类 我有下面的C++代码,这说明了我的问题。 我的目标是重写继承类中的stream操作符,以便根据对象类型打印特定流: #include <iostream> #include <unordered_set> using namespace std; template <typename T> class Base { public: Base(){} Base(T n): value_(n){} friend inline ostream &operator<<(ostream &os, const Base &b) { b.to_str(os); return os; } protected: T value_; // All object should implement this function virtual void to_str(ostream& os) const { os << value_; } }; template <typename T> class Child: public Base<T> { public: Child(T n): Base<T>(n){} protected: void to_str(ostream& os) const override { os << "{"; for (auto v = this->value_.begin(); v != this->value_.end(); v++) { if(v != this->value_.begin()) os << ","; os << (*v); } os << "}"; } }; int main() { Base<string> b("base"); Child<unordered_set<string>> c({"child"}); cout << "b: " << b << endl; cout << "c: " << c << endl; return 0; } #包括 #包括 使用名称空间std; 模板 阶级基础{ 公众: Base(){} 基(tn):值_un{} friend inline ostream&operator,c++,inheritance,operator-overloading,operator-keyword,C++,Inheritance,Operator Overloading,Operator Keyword,编译基to_str,即使它从未运行过 所以 virtualvoid to_str(ostream&os)const{ 实际上,虚拟调用确实发生了。您可以通过将代码更改为 template <typename T> class Base { public: Base(){} Base(T n): value_(n){} friend inline ostream &operator<<(ostream &am

编译基
to_str
,即使它从未运行过

所以

virtualvoid to_str(ostream&os)const{

实际上,虚拟调用确实发生了。您可以通过将代码更改为

template <typename T>
class Base {
    public:
        Base(){}
        Base(T n): value_(n){}

        friend inline ostream &operator<<(ostream &os, const Base &b) {
            b.to_str(os);
            return os;
        }

    protected:

        T value_;

        virtual void to_str(ostream& os) const = 0;
};

template <typename T>
class Child: public Base<T> {
    public:
        Child(T n): Base<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << "{";
            for (auto v = this->value_.begin(); v != this->value_.end(); v++) {
                if(v != this->value_.begin())
                    os << ",";
                os << (*v);
            }
            os << "}";
        }
};

int main()
{
    Child<unordered_set<string>> c({"child"});
    cout << "c: " << c << endl;
    return 0;
}

这个函数是无效的,因为这是我最后用“纯虚拟解决方案”实现的, 使用一些更基本的类型进行测试:

#include <iostream>
#include <unordered_set>

using namespace std;

template <typename T>
class Base_ {

    public:
        Base_(){}
        Base_(T n): value_(n){}

        friend inline ostream &operator<<(ostream &os, const Base_ &b) {
            b.to_str(os);
            return os;
        }

    protected:
        T value_;

        // All object should implement this function
        virtual void to_str(ostream& os) const = 0;
};

template <typename T>
class Base: public Base_<T> {
    public:
        Base(){}
        Base(T n): Base_<T>(n){}

    protected:

        // All object should implement this function
        void to_str(ostream& os) const override {
            os << this->value_;
        }
};

template <typename T>
class Child: public Base_<T> {
    public:
        Child(T n): Base_<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << "{";
            for (auto v = this->value_.begin(); v != this->value_.end(); v++) {
                if(v != this->value_.begin())
                    os << ",";
                os << (*v);
            }
            os << "}";
        }
};

template <typename T>
class Boolean: public Base_<T> {
    public:
        Boolean(T n): Base_<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << (this->value_ ? "true" : "false");
        }
};

int main()
{
    Base<string> s("string");
    Base<int> i(42);
    Boolean<bool> b(true);
    Child<unordered_set<string>> u({"child1", "child2"});
    cout << "s: " << s << endl;
    cout << "i: " << i << endl;
    cout << "b: " << b << endl;
    cout << "u: " << u << endl;

    return 0;
}
#包括
#包括
使用名称空间std;
模板
类基类{
公众:
基函数{}
基(n):值(n){
friend inline ostream&operatorvalue_uz.begin())

os您没有正确复制错误消息。缺少部分。它将始终使用
子版本的
to_str()
。但是comiler仍然希望为
std::unordered_set
生成函数
Base::to_string()
,这是合理的,因为它仍然可以被调用(并且在构建Base的过程中需要地址来正确构建V-Table(假设实现使用V-Tables)
pure virtual在基础中。然后必须为Child和一个新的类StandardStremable派生实现。@MartinYork感谢您的提示,正在考虑一个类似于您建议的解决方案。我将发布修改后的代码。感谢您的回答,我将发布一个具有纯虚拟实现的解决方案很高兴知道这是xist!!!我将实施纯虚拟解决方案,因为它对我来说更清晰。无论如何,谢谢你
template <class T, class D_in=void>
class Base {
    using D=std::conditional_t< std::is_same<D_in,void>{}, Base, D_in >;
    public:
        Base(){}
        Base(T n): value_(n){}

        friend inline ostream &operator<<(ostream &os, const Base &b) {
            static_cast<D const&>(b).to_str(os);
            return os;
        }

    protected:

        T value_;

        // All object should implement this function
        void to_str(ostream& os) const {
            os << value_;
        }
};

template <typename T>
class Child: public Base<T, Child<T>> {
    friend class Base<T, Child<T>>;
    public:
        Child(T n): Base<T>(n){}

    protected:
        void to_str(ostream& os) const {
         os << "{";
            for (auto v = this->value_.begin(); v != this->value_.end(); v++) {
                if(v != this->value_.begin())
                    os << ",";
                os << (*v);
            }
            os << "}";
        }
};
template <typename T>
class Base {
    public:
        Base(){}
        Base(T n): value_(n){}

        friend inline ostream &operator<<(ostream &os, const Base &b) {
            b.to_str(os);
            return os;
        }

    protected:

        T value_;

        virtual void to_str(ostream& os) const = 0;
};

template <typename T>
class Child: public Base<T> {
    public:
        Child(T n): Base<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << "{";
            for (auto v = this->value_.begin(); v != this->value_.end(); v++) {
                if(v != this->value_.begin())
                    os << ",";
                os << (*v);
            }
            os << "}";
        }
};

int main()
{
    Child<unordered_set<string>> c({"child"});
    cout << "c: " << c << endl;
    return 0;
}
Base<unordered_set<string>>::to_str
#include <iostream>
#include <unordered_set>

using namespace std;

template <typename T>
class Base_ {

    public:
        Base_(){}
        Base_(T n): value_(n){}

        friend inline ostream &operator<<(ostream &os, const Base_ &b) {
            b.to_str(os);
            return os;
        }

    protected:
        T value_;

        // All object should implement this function
        virtual void to_str(ostream& os) const = 0;
};

template <typename T>
class Base: public Base_<T> {
    public:
        Base(){}
        Base(T n): Base_<T>(n){}

    protected:

        // All object should implement this function
        void to_str(ostream& os) const override {
            os << this->value_;
        }
};

template <typename T>
class Child: public Base_<T> {
    public:
        Child(T n): Base_<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << "{";
            for (auto v = this->value_.begin(); v != this->value_.end(); v++) {
                if(v != this->value_.begin())
                    os << ",";
                os << (*v);
            }
            os << "}";
        }
};

template <typename T>
class Boolean: public Base_<T> {
    public:
        Boolean(T n): Base_<T>(n){}

    protected:
        void to_str(ostream& os) const override {
         os << (this->value_ ? "true" : "false");
        }
};

int main()
{
    Base<string> s("string");
    Base<int> i(42);
    Boolean<bool> b(true);
    Child<unordered_set<string>> u({"child1", "child2"});
    cout << "s: " << s << endl;
    cout << "i: " << i << endl;
    cout << "b: " << b << endl;
    cout << "u: " << u << endl;

    return 0;
}