继承的静态工厂方法返回子 Class 类型

Inherited Static Factory Method Returning Child Class Type

我有一个 Logging class 被 LoggingStringLoggingInt 等继承,每个都有一个 writeLog 函数接受对应类型:

class Logging {
public:
    explicit Logging(const LoggingConfig& config);
...
}

class LoggingString : public Logging {
public:
    using Logging::Logging;

    writeLog(std::string str);
...
}

在我使用 LoggingString 的代码中,我希望能够像这样调用工厂函数:

std::unique_ptr<LoggingString> logger = LoggingString::CreateIfLoggingEnabled(LoggingConfig{...});
std::unique_ptr<LoggingInt> logger = LoggingInt::CreateIfLoggingEnabled(LoggingConfig{...});

考虑到它们都使用从基础 Logging class 派生的相同构造函数,是否可以将此 static Logging::CreateIfLoggingEnabled 函数放在基础 class 中并且它以某种方式被 Logging 派生的 classes 继承,但返回的是 unique_ptr<LoggingDerivedClass>?也许像这样的模板:

class Logging {
public:
    explicit Logging(const LoggingConfig& config);

    template<typename T> static std::unique_ptr<T> CreateIfLoggingEnabled(const LoggingConfig& config) {
        ...
        return std::unique_ptr<T>{};
    }
...
}

std::unique_ptr<LoggingString> logger = LoggingString::CreateIfLoggingEnabled<LoggingString>(LoggingConfig{...});

不确定这是否可行,而且必须指定 LoggingString 两次似乎是多余的。还有其他选择吗?

it seems redundant to have to specify LoggingString twice.

您不必指定 LoggingString 两次(如果算上 logger 变量声明三次)。可以用Logging::代替LoggingString::,变量用auto,例如:

class Logging {
public:
    explicit Logging(const LoggingConfig& config);

    template<typename T>
    static std::unique_ptr<T> CreateIfLoggingEnabled(const LoggingConfig& config) {
        ...
        return std::make_unique<T>(config);
    }
    ...
};
auto logger = Logging::CreateIfLoggingEnabled<LoggingString>(LoggingConfig{...});
auto logger = Logging::CreateIfLoggingEnabled<LoggingInt>(LoggingConfig{...});

Demo

或者,您可以使用 CRTP 将派生类型传递到基础 class,例如:

template<typename Derived>
class Logging {
public:
    explicit Logging(const LoggingConfig& config);

    static std::unique_ptr<Derived> CreateIfLoggingEnabled(const LoggingConfig& config) {
        ...
        return std::make_unique<Derived>(config);
    }
    ...
};

class LoggingString : public Logging<LoggingString> {
public:
    using Logging<LoggingString>::Logging;

    void writeLog(std::string str);
    ...
};

class LoggingInt : public Logging<LoggingInt> {
public:
    using Logging<LoggingInt>::Logging;

    void writeLog(int i);
    ...
};
auto logger = LoggingString::CreateIfLoggingEnabled(LoggingConfig{...});
auto logger = LoggingInt::CreateIfLoggingEnabled(LoggingConfig{...});

Demo