我想很长一段时间使用虚函数,类对象必须用指针分配,但我运行了一个测试示例,它似乎对于堆栈上的对象完全有效,它只取决于你如何调用它的语法.但我正在做的事情几乎就像我正在创建一个'作弊'来使系统做我想要的,即使用普通的基类指针来调用派生类的虚方法.
#include <iostream>
using namespace std;
class B{
public:
virtual void call() { cout<<"B\n"; };
};
class D: public B{
public:
void call() { cout<<"D\n"; }
};
int _tmain(int argc, _TCHAR* argv[])
{
B b;
D d;
b.call(); // output is "B"
d.call(); // output is "D"
B* obj = &d;
obj->call(); // output is "D"
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这在发布软件中是否可以接受,还是会引起人们的注意?我可以在我的软件中使用它,但我之前没有见过这样的东西.
在我的实际项目中,我有基类和派生类,它们在堆栈上分配,让我们调用它们Base,DerivedA和DerivedB.我想重组并向基础添加虚函数,我想我现在必须在堆上分配它们,但看起来我没必要.现在我的应用程序可以在某些状态下,所有的操作都将完成DerivedA或DerivedB因此我打算增加一个指针对象:
Base * obj = &DerivedA;
Run Code Online (Sandbox Code Playgroud)
显然,当我需要切换操作到其他对象时,我只是这样做obj = &DerivedB,基本上我将通过我的新obj指针间接使用这两个对象进行所有操作.这听起来不错吗?
目前我的代码有if else声明可以在DerivedA或上执行操作DerivedB,这将消除这些.
这是完全正常的.C++的一个重要原则是对象不应该关心谁拥有它们 - 包括堆栈.在同一个堆栈框架中持有一个指向派生对象的基指针并不常见,因为这会引发一个问题,为什么你不是直接使用它,但是多态地引用自动存储持续时间对象是完全合法和常见的. .
请注意,我说"自动存储持续时间"而不是"在堆栈上".这是因为相同的规则适用于任何自动存储持续时间对象类成员是最明显的例子.
指向堆中对象的指针,指向堆栈中对象的指针或内存中其他任何地方的指针之间没有区别。
堆栈上的对象或堆上的对象之间没有(内部)区别:它们具有相同的成员,包括v-table指针,无论如何。
因此,您所做的完全可以接受。当以本地对象作为参数调用以指针作为参数的函数时,可以看到该惯用语的更常见版本:
MyObj foo;
MyFunc(&foo);
Run Code Online (Sandbox Code Playgroud)
考虑到此调用的“ C”方式,即给出的实际参数是的地址 foo,在此处提供了一些见解:这是将指向堆栈局部对象的指针传递给函数的标准方式。当然,在该函数的主体内,无法知道对象是在堆栈上,在堆上还是在其他地方。因此,我们希望对虚拟函数的处理方式相同。
当然,有一个警告,那就是永远不要在堆栈上将对象声明为指针(例如MyObj* foo = &foo{};)。看到这里是我的一个旧答案,我完全拒绝了这个答案(尽管我后来编辑了这个问题,以使新观众清楚我的示例是不好的做法,即使它在某些情况下也可以在某些编译器中使用;请查看编辑历史记录以查看答案的原始版本,这使我赢得了一些当之无愧的赞誉。
编辑:您可以考虑使用引用,而不是直接使用指针。下面是一个完整的示例程序,演示了此过程:
#include <iostream>
using namespace std;
class Base
{
public:
virtual const char* func()
{
return "Base::foo\n";
}
};
class Derived: public Base
{
public:
virtual const char* func()
{
return "Derived::foo\n";
}
};
inline Base& pickObj (int i, Base& obj1, Base& obj2)
{
if (i > 0)
{
return obj1;
}
else
{
return obj2;
}
}
int main()
{
Base base;
Derived derived;
Base& my_obj{pickObj(0, base, derived)};
cout << my_obj.func();
}
Run Code Online (Sandbox Code Playgroud)
运行时,输出为:
Derived::foo
Run Code Online (Sandbox Code Playgroud)