使用数组对对象的编译时多态性是否可行?

Is Compile Time Polymorphism Of Objects Using Arrays Possible?

本文关键字:是否 多态性 编译 数组 对象      更新时间:2023-10-16

我还在学习,我有一个问题,希望有人能帮助我:

是否可以在不使用虚函数的情况下实现从同一基类继承的不同类的编译时多态性,以便在数组中使用?

作为任何知道一点 OOP 的人,如果你有类似的东西,C++

class Base {
public:
virtual void foo (){
std::cout << "I'm the base" << std::endl;
}
}
class A : public Base {
public:
void foo() {
std::cout << "I'm the child" << std::endl;
}
} 
class B : public Base {
public:
void foo() {
std::cout << "I'm the child #2" << std::endl;
}
} 

//Assume some main here
A *a = new A();
B *b = new B();
Base *someArray[] = {a,b};
someArray[0]->foo(); //"I'm the child"
someArray[1]->foo(); //"I'm the child #2"

我们知道这是有效的,因为函数是和继承在运行时解析的。但是,我要知道的是如何在没有虚函数的情况下做到这一点,或者是否可以在不使用虚函数的情况下做同样的事情?

假设你做这样的事情

class Base {
public:
void foo (){
std::cout << "I'm the base" << std::endl;
}
}
class A : public Base {
public:
void foo() {
std::cout << "I'm the child" << std::endl;
}
} 
class B : public Base {
public:
void foo() {
std::cout << "I'm the child #2" << std::endl;
}
} 

//Assume some main here
A *a = new A();
B *b = new B();
Base *someArray[] = {a,b};
someArray[0]->foo(); //"I'm the base"
someArray[1]->foo(); //"I'm the base"

所以有很多选择,但我似乎找不到具有我想要的相同行为的东西。我读到的一个解决方案是制作一个静态类模板,其工作方式如下

template <class T>
class Base
{
public:
void interface()
{
// ...
static_cast<T*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
T::static_sub_func();
// ...
}
};
class Derived : Base<Derived>
{
public:
void implementation() {
std::cout << "I am derived" << std::endl;
}
static void static_sub_func();
};
class AlsoDerived : Base<Derived>
{
public:
void implementation() {
std::cout << "I am also derived" << std::endl;
}
static void static_sub_func();
};

//Assume in some main 
Derived div;
AlsoDerived alsoDiv;
Derived *someArray[] = { &div, &alsoDiv };//does not work not the same type 
Base *someArray[] = { &div, &alsoDiv }; //does not work b/c its a template 

以上不是我想要的行为。然后是静态转换,这似乎很有前途,但是我需要知道在任何给定时间它会是什么类,这不是我想要的行为。

class Base {
public:
void foo (){
std::cout << "I'm the base" << std::endl;
}
}
class A : public Base {
public:
void foo() {
std::cout << "I'm the child" << std::endl;
}
} 
class B : public Base {
public:
void foo() {
std::cout << "I'm the child #2" << std::endl;
}
} 

//Assume some main here
A *a = new A();
A *b = new A();
B *c = new B();
Base *someArray[] = {a,b,c};
someArray[0]->foo(); //"I'm the base"
static_cast<A*>(someArray[1])->foo(); //"I'm the child"
static_cast<B*>(someArray[2])->foo(); //"I'm the child #2"

这非常接近我想要的,但是我的问题是要使static_cast工作,我需要知道我想要静态大小写的是什么类,而不是我想要的行为。

你觉得怎么样?有没有更好的方法做我想做的事?

感谢您的阅读,如果对我所问的内容有任何困惑,请告诉我,以便我澄清。

在编译时没有真正的方法可以做你想做的事情。 仅仅因为您希望您的行为取决于运行时对象的类型。

C++通过多态性(即使用虚函数)和 RTTI(如果需要)提供运行时类型依赖行为。 如果您不想使用这种"自然方式",您将有以下选择:

  • 你知道编译时对象的类型(例如,如果你确定第一个元素始终是A*,第二个元素始终是B*):在这种情况下,您可以使用static_cast,就像在第三种情况下一样,或者使用模板化代码(例如,如果您更喜欢编译时策略而不是运行时策略)。 但这通常不是处理容器中随机对象的方法。
  • 您可以自己找出对象的类型并推断出要调用的相应函数: 执行此操作的典型方法是在基类中有一个键入字段,并使用它来向下转换static_cast。但这不是最佳做法。 添加自己的类似RTTI的功能而不是使用编译器的优化功能不会比多态更有效。
  • 您可以使用std::variantstd::any:这些提供了使用编译时功能提供某种运行时相关行为的可能性(不一定要求从公共基派生替代类型)。

剩下的问题是,如果需要,为什么要避免正常的多态性。