在 c++ 中类继承的情况下强制延迟方法解析
Forcing late method resolution in case of class inheritance in c++
考虑以下类结构:-
class foo {
public:
int fun () {
cout << "in foo" << endl;
}
};
class bar_class1:public foo {
public:
int fun () {
cout << "in bar_class1" << endl;
}
};
class bar_class2:public foo {
public:
float fun () {
cout << "in bar_class2" << endl;
}
};
main () {
foo * foo_pointer = new bar_class1();
foo_pointer->fun();
}
上述程序的输出在 foo 中。有没有办法,使用实际上指向 bar_class1
或 bar_class2
类型的对象的类型 foo *
的指针,我们可以调用派生类的 fun
函数而不是基类?我无法在基类foo
中使fun
函数成为虚拟函数,因此派生类bar_class2
中的函数foo
存在返回类型冲突。
这是我的评论作为答案。
你不能那样做。
如果这种多态性是可能的,那么当代码在实际类型为 bar_class2 的对象上调用 foo::fun
(期望一个 int)并因此获得浮点数时,这不会严重中断吗?你想简单地扔掉类型安全吗?
如果你想要不同的返回类型,听起来你想要一个模板。但是你不能完全按照你想使用 foo() 的方式使用模板。静态多态性(模板)和运行时多态性(后期绑定)不能很好地混合。你需要重新设计你的 oop 结构。
如果你绝对讨厌类型安全,你可以用 void 指针来做到这一点。 但是为了对飞行意大利面怪物的热爱,永远不要在 c++ 中这样做。请在阅读以下代码之前闭上眼睛以避免暴露。
#include <iostream>
class foo {
public:
virtual void* fun() = 0;
virtual ~foo(){};
};
class bar_class1: public foo {
public:
void* fun() {
return &value;
}
private:
int value = 1;
};
class bar_class2: public foo {
public:
void* fun() {
return &value;
}
private:
float value = 1.1;
};
int main() {
foo* foo_pointer1 = new bar_class1();
foo* foo_pointer2 = new bar_class2();
// in c++ compiler must know the type of all objects during compilation
std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << 'n';
std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << 'n';
delete foo_pointer1;
delete foo_pointer2;
}
也许与现有的答案类似,我真的希望你意识到改变你的设计比这种混乱更好,但我相信这是你会得到的最好的。我强迫您在调用站点指定返回类型(例如,someFoo->fun<int>()
),因为无论如何您都必须知道它,并基于此进行调度。任何有趣的生意,你都会得到一个例外。还要记住,我想,这种性能是不太理想的。
#include <cassert>
#include <stdexcept>
#include <type_traits>
struct foo {
virtual ~foo() = default;
template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
T fun();
template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
T fun();
};
struct bar_class1 : foo {
int fun() {
return 2;
}
};
struct bar_class2 : foo {
float fun() {
return 3.5f;
}
};
template<typename T, typename, typename Dummy>
T foo::fun() {
if (auto *p = dynamic_cast<bar_class1 *>(this)) {
return p->fun();
} else if (dynamic_cast<bar_class2 *>(this)) {
throw std::invalid_argument("Mismatching dynamic type.");
} else {
return 1;
}
}
template<typename T, typename>
T foo::fun() {
auto *p = dynamic_cast<bar_class2 *>(this);
if (dynamic_cast<bar_class1 *>(this) || !p) {
throw std::invalid_argument("Mismatching dynamic type.");
} else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
return p->fun();
}
assert(false); //should never get here, but compiler doesn't know that
}
如果你想要 main 函数,我已经写了一个完整的示例。
回答您的问题:不,如果不决定返回类型,就不可能进行后期绑定。至少不是以合理的方式,请参阅 User2079303 的精彩反例。但。。。
例如,您可以使用关键字 virtual
将代码更改为如下所示的内容,并将 Instance 的返回类型均衡为 void
:
class foo
{
public:
virtual void fun(std::ostream& out) {
out << "in foo" << std::endl;
}
};
因此,您可以稍后决定输出类型:
class intFoo: public foo
{
public:
void fun(std::ostream& out) {
// output an int
out << "in bar_class1. data: " << data << endl;
}
int data;
};
class floatFoo: public foo
{
public:
void fun(std::ostream& out) {
// output a float
out << "in bar_class2. data: " << data << endl;
}
float data;
};
为简洁起见,我双重使用输出流(现在是函数fun()
的参数)来演示派生类的类型相关部分。在应用程序中,参数可能是另一种更有用的类型。
函数fun不是虚拟函数,因为你没有使用关键字"virtual"来装饰它。因此,编译将确定在编译时调用哪个函数。因此,没有办法告诉编译器调用另一个函数,因为编译器将使用其静态类型,即变量定义类型 -- foo *。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 我希望改进或要求我目前的延迟/睡眠方法。C++
- 延迟shared_ptr<>在C++中被破坏的最佳方法
- C++11 延迟执行的"correct"方法
- 在 c++ 中类继承的情况下强制延迟方法解析
- WiX c ++ :: 在延迟的 ca 中使用 dll 条目的正确方法
- 由于在C++中使用了异步IO,因此在不休眠的情况下延迟程序的其他方法
- 有没有一种方法可以延迟初始化类的静态子对象
- 什么是Qt中低延迟音频合成的最佳多线程方法
- 在c++中实现延迟求值的一种方法