【发布时间】:2015-08-12 02:10:42
【问题描述】:
考虑这个输出:
Current time: 6:30 pm
Current time: 18:30
Current time: evening.
Current time: evening (for many it is dinner time, but many eat dinner later).
请注意,最后两个有句号,而前两个没有。我从下面的代码中使用System::displayCurrentTime 成员函数获得了这个所需的输出:
#include <iostream>
#include <string>
#include <memory>
class TimeDisplay {
public:
virtual std::string tell() const = 0;
virtual std::string tellMaybeWithPeriod() const = 0;
};
class ClockDisplay12Hours : public TimeDisplay { // #1
std::string tell() const override {return "6:30 pm";}
std::string tellMaybeWithPeriod() const override {return tell();}
};
class ClockDisplay24Hours : public TimeDisplay { // #2
std::string tell() const override {return "18:30";}
std::string tellMaybeWithPeriod() const override {return tell();}
};
class DescriptiveTimeDisplay : public TimeDisplay { // #3
std::string tell() const override {return "evening";}
std::string tellMaybeWithPeriod() const override {return tell() + ".";}
};
class CrazyDescriptiveTimeDisplay : public TimeDisplay { // #4
std::string tell() const override {return "evening (for many it is dinner time, but many eat dinner later)";}
std::string tellMaybeWithPeriod() const override {return tell() + ".";}
};
struct System {
static std::shared_ptr<TimeDisplay> timeDisplay;
static std::string timeAsString() {return timeDisplay->tell();}
static std::string timeAsStringMaybeWithPeriod() {return timeDisplay->tellMaybeWithPeriod();}
// #3 and #4 will have a period, the others will not.
static void displayCurrentTime (std::shared_ptr<TimeDisplay> t) {
timeDisplay = t;
std::cout << "Current time: " << System::timeAsStringMaybeWithPeriod() << '\n';
}
static void foo (std::shared_ptr<TimeDisplay>) {} // #1 and #3 will have a period, the others will not.
static void bar (std::shared_ptr<TimeDisplay>) {} // #1, #2, and #4 will have a period, the others will not.
static void baz (std::shared_ptr<TimeDisplay>) {} // #2 will have a period, the others will not
};
std::shared_ptr<TimeDisplay> System::timeDisplay;
int main() {
const std::shared_ptr<TimeDisplay> clocks[] = {std::make_shared<ClockDisplay12Hours>(), std::make_shared<ClockDisplay24Hours>(),
std::make_shared<DescriptiveTimeDisplay>(), std::make_shared<CrazyDescriptiveTimeDisplay>()};
for (std::shared_ptr<TimeDisplay> t : clocks)
System::displayCurrentTime(t);
}
这不是很乱,但请注意,下一个实现foo、bar、baz 的函数需要TimeDisplay 的不同派生类的句点,而实际上有不止4 个这样的派生类,还有超过 3 个新的成员函数需要处理。有没有比为foo、bar、baz 等每个写出新的虚函数更简洁更优雅的方式来处理这些即将到来的成员函数... ?以某种方式使用模板(例如,重命名派生类Derived<0>、Derived<1> 等......然后使用这些编译时整数来适应上面 cmets 中所述的规则)?或许可以避免使用模板并做其他事情?
【问题讨论】:
-
请澄清您的问题。
-
如何最好地实现
foo、bar、baz等...通过遵循上述cmets 中所述的规则,而不重复displayCurrentTime造成的混乱?否则,新的虚函数的数量就会爆炸式增长。我将foo、bar、baz留空,因为只有期间业务需要担心。 -
使用以下代码有什么问题:
static void displayCurrentTime (std::shared_ptr<TimeDisplay> t) { std::cout << "Current time: " << t->tellMaybeWithPeriod() << '\n'; } -
因为
tellMaybeWithPeriod()仅适用于#3 和#4 获取期间。上面提到的所有其他情况呢? -
所以有 4 种不同的显示类型可以传递给 4 个不同函数中的任何一个,每个函数都有不同的尾随句点存在规则。是的,这显然是在创造 4x4=16 的可能性……我的第一反应不是试图解决这个设计,而是回到实际需求,看看是否有不同的方法来完全处理这个问题。 (例如,一个接受两个参数的函数:显示类型和是否有句点的布尔值。)
标签: c++ inheritance virtual