如何实现可派生的C ++类字符串表示,包括类名

时间:2018-03-02 16:40:11

标签: c++

我来自python世界,其中__str____repr__对我的开发和执行工作流输出非常有用。 我想用C ++实现这些东西。 This post一直很有用,但我希望字符串输出包含类名,并且子类可以轻松地重载。 这是一个代码示例:

#include<iostream>
#include<string>

class Parent
{
    static constexpr const char* clsName = "Parent";
    std::string _label;
public:
    Parent(std::string& label) : _label(label) {}

    friend std::ostream &operator<<(std::ostream &os, 
                                    Parent const &ref)
    {   
        os << clsName << "(";
        ref.print(os); 
        os << ")";
        return os; 
    }
    void print(std::ostream &os) const
    { os << _label; }
};

class Child : public Parent
{
    static constexpr const char* clsName = "Child";
public:
    Child(std::string& label) : Parent(label) {}
};

我的意图是Child::operator<<使用它自己的clsName静态私有数据,而不必为每个子类重载整个运算符。 不幸的是,这种策略不起作用:

int main()
{
    std::string l("some label");
    Child x(l);
    std::cout << x << std::endl;
}

将输出

Parent(some label)

(我希望看到Child(some label))。

2 个答案:

答案 0 :(得分:1)

我会添加一个virtual成员函数来获取类名。

我还会使print成为virtual成员函数,以允许派生类增强在基类中完成的操作。

我建议进行更多改进:

  1. 使构造函数的参数为​​const&
  2. operator<<功能不一定是friend
  3. 这是您课程的更新版本。

    class Parent
    {
       private:
          static constexpr const char* clsName = "Parent";
          std::string _label;
    
       public:
          Parent(std::string const& label) : _label(label) {}
    
          virtual std::string getClassName() const
          {
             return clsName;
          }
    
          virtual void print(std::ostream &os) const
          {
             os << _label;
          }
    };
    
    std::ostream &operator<<(std::ostream &os, Parent const &ref)
    {   
       os << ref.getClassName() << "(";
       ref.print(os); 
       os << ")";
       return os; 
    }
    
    class Child : public Parent
    {
       private:
          static constexpr const char* clsName = "Child";
    
       public:
          virtual std::string getClassName() const
          {
             return clsName;
          }
    
          virtual void print(std::ostream &os) const
          {
             // Nothing to do for this class in particual.
             // Just use the Parent implementation.
             Parent::print(os);
          }
    
          Child(std::string const& label) : Parent(label) {}
    };
    

答案 1 :(得分:0)

您需要使clsName成为虚拟功能。目前Child::clsName仅隐藏Parent::clsName,您仍可以Parent::clsName内访问Child

您还应该声明Parent的析构函数是虚拟的,这意味着还应该声明其他特殊成员。所有五个都可以实现为= default

#include<iostream>
#include<string>

class Parent
{
    virtual std::string clsName() const { return "Parent" };
    std::string _label;
public:
    Parent(const std::string& label) : _label(label) {}
    virtual ~Parent() = default;
    Parent(const Parent &) = default;
    Parent(Parent &&) = default;
    Parent& operator=(const Parent &) = default;
    Parent& operator=(Parent &&) = default;

    friend std::ostream &operator<<(std::ostream &os, Parent const &ref)
    {   
        return os << ref.clsName() << "(" << ref._label << ")";
    }
};

class Child : public Parent
{
    std::string clsName() const override { return "Child" };
public:
    using Parent::Parent;
};