【发布时间】:2021-10-16 18:57:51
【问题描述】:
我想要做的是暴露一个成员函数的名字告诉其他开发者每个派生类都必须实现接口中暴露的同名的特定函数,但是实现的函数可以使用不同的签名。
要使用gtest测试接口,我必须保留示例中的虚函数:
class Fruit {};
class Meat {};
class Finger {};
class Animal {
public:
virtual void eat(/* something */) = 0;
};
class Monkey : public Animal {
public:
void eat(Fruit fruit, Finger finger) override {
std::cout << "I eat fruits and suck my fingers" << std::endl;
}
};
class Dog : public Animal {
public:
void eat(Meat meat) override {
std::cout << "I eat meat" << std::endl;
}
};
int main() {
Meat meat;
Fruit fruit;
Finger finger;
Monkey monkey;
Dog dog;
monkey.eat(fruit, finger);
dog.eat(meat);
}
看完后:
- How to achieve “virtual template function” in C++
- C++ force implementation of method in child class but with a different signature
我知道有两种可能的解决方案,一种是使用调度程序,另一种是使用 CRTP。
调度员: 此解决方案会破坏类型检查。
class EatDispatcherInterface {
public:
virtual void eat(Monkey* monkey) = 0;
virtual void eat(Dog* dog) = 0;
};
class EatDispatcher : public EatDispatcherInterface {
public:
EatDispatcher(Fruit fruit) : food(fruit) {}
EatDispatcher(Meat meat) : food(meat) {}
void eat(Monkey* monkey) override {
std::cout << "I eat fruits" << std::endl;
}
void eat(Dog* dog) override {
std::cout << "I eat meat" << std::endl;
}
private:
union {
Fruit fruit;
Meat meat;
} food;
};
class Fruit {};
class Meat {};
class Animal {
public:
virtual void accept(const EatDispatcher& eat_dispatcher) = 0;
};
class Monkey : public Animal {
public:
void eat(const EatDispatcher& eat_dispatcher) override {
eat_dispatcher.eat(this);
}
};
class Dog : public Animal {
public:
void eat(const EatDispatcher& eat_dispatcher) override {
eat_dispatcher.eat(this);
}
};
int main() {
EatDispatcher fruit_eat_dispatcher(Fruit());
EatDispatcher meat_eat_dispatcher(Meat());
Monkey monkey;
Dog dog;
monkey.accept(fruit_eat_dispatcher);
dog.accept(meat_eat_dispatcher);
}
CRTP: 这个解决方案在接口中暴露了派生类的细节。
class Fruit {};
class Meat {};
template <typename Food>
class Animal {
public:
virtual void eat(Food food) = 0;
};
class Monkey : public Animal<Fruit> {
public:
void eat(Fruit fruit) {
std::cout << "I eat fruits" << std::endl;
}
};
class Dog : public Animal<Meat> {
public:
void eat(Meat meat) {
std::cout << "I eat meat" << std::endl;
}
};
int main() {
Monkey monkey;
Dog dog;
monkey.eat(Fruit());
dog.eat(Meat());
}
正确的模式是什么?有没有没有这些缺点的其他解决方案?
版权所有 2021 Google LLC。
SPDX 许可证标识符:Apache-2.0
【问题讨论】:
-
@Ruks 它不会再覆盖基类,它将是一个具有不同签名的新函数
-
当您的基类是模板类时,它不再可用作基类。该模板使其对每种食物都独一无二。
-
我没有看到多态性的任何用途,因此您的示例中需要虚函数?
-
"我想要做的是暴露一个成员函数的名字告诉其他开发者每个派生类都必须实现接口中暴露的同名的特定函数,但是实现的函数可以使用不同的签名。”这只是文档吗?如果您不知道如何调用
eat成员函数,那么知道它的存在有什么帮助?
标签: c++ design-patterns