我想为返回消息的类创建一个接口。我的问题是,有时返回一个字符串会更好,有时返回一个const string&会更好。为继承类提供选择返回类型的可能性的最佳方法是什么?

struct Verbose{
   // my message is a class member
   virtual const string& getMsg()const=0;

   // my message is created in the function
   virtual string getMsg()const=0;
};

我想要这样的东西,而不是这个接口,以便提供这种灵活性

struct Verbose{
   virtual myPrintableType getMsg()const=0;
};

1

  • 返回类型不是函数签名的一部分,因此您会遇到。您能否说明您真正想要实现的目标,以便能够给您相关的答案?


    – 


3 个回答
3

您可以对成员函数使用

struct Verbose{
   virtual const std::string& getMsg() const& = 0;
   virtual std::string getMsg() const&& = 0;
};

struct Derived: Verbose {
    std::string s{"xxx"};
    const std::string& getMsg()const& {
        std::cout << "const string&\n";
        return s;
    }
    std::string getMsg()const&& {
        std::cout << "string\n";
        return "yyy";
    }
};

仅当您的对象是左值时才会调用第一个版本,即通过 const 引用返回成员字段被认为是安全的。第二个版本将被称为 r 值。

    Derived d;
    std::cout << d.getMsg() << std::endl;  // calls 1st overload
    std::cout << Derived{}.getMsg() << std::endl;  // calls 2nd overload

这是假设您希望根据值类别有不同的行为。如果情况并非如此,并且您需要为同一值类别使用不同的返回类型,那么您需要 2 个不同的函数。

1

  • 1
    这正是我一直在寻找的!谢谢 :)


    – 

该函数无法选择——您只能返回一种类型。重载(具有不同类型的相同函数名称)仅适用于参数类型 – 是的,如果您的函数采用不同的参数类型,它们也可能返回不同的结果类型。

但是,如果调用者可以做出决定,那么它当然可以调用一个或另一个函数。就像我有这个API:

template <typename T> const T& get() const requires (!std::is_scalar_v<T>);
template <typename T> T get() const requires (std::is_scalar_v<T>);

当然,我只能这样做,因为调用者知道它会得到什么。我最终可能会删除标量版本。

就您而言,消息通常只是基类,并且您通常可以始终返回std:unique_ptrstd::shared_ptr(取决于消息的工作方式)。当然,如果它真的只是字符串,那么就决定一个版本。

不幸的是,不可能完全按照您所描述的操作,因为基于返回类型的重载是不可能的。不过你可以使用常量

struct Verbose{
  
   virtual const string& getMsg()const=0;

   //Either return string
   virtual string getMsg()=0;

   //Or a reference
   virtual string& getMsg()=0;
};

如果要在调用代码中使用字符串的副本,可以使用返回常量引用的 const 函数。此函数重载更加“通用”,因为它允许用户决定如何处理字符串,并且不会强制他们执行复制。