永久向下转换c++指针

Permanently Downcast c++ Pointer

本文关键字:c++ 指针 转换      更新时间:2023-10-16

这可能是一个奇怪的问题,但我有一个相当好的理由问。

我的问题的要点是,给出一个在类层次结构上具有两级派生的示例:

主基类:

class Animal
{
  virtual void Draw() = 0;
};

派生类:

class Dog : public Animal
{
  virtual void Draw()
  {
    // draw a generic dog icon or something...
  }
};

进一步推导:

class Corgi : public Dog
{
  virtual void Draw()
  {
    // draw a corgi icon...
  }
};

现在,我希望能够,从Corgi类内,永久向下cast 'this'指针到Dog指针,然后将其传递到其他地方作为动物。然后,这个其他地方将能够调用Draw函数并获得Dog方法,而不是虚拟的Corgi方法。我知道这很奇怪,但是,我有一个模糊的合理的理由想要这样做。

我尝试了所有不同的强制转换操作符,但没有任何运气,但也许有一个一致的方法来实现这一点?在过去,我因为没有正确使用dynamic_cast而导致指针的类似状态而给自己带来麻烦。也许这次我可以利用这一点?

编辑:

也许上面的例子不能清楚地说明我想要达到的目标,所以我将详细说明我的真正目标。

我试图实现一个速记注册基类实现链接到一个脚本系统,我已经使用了一段时间。脚本系统依赖于一个基类IScriptContext来方便访问实际代码函数和成员变量。在内部基类注册它们的成员函数地址和成员变量地址,这些地址稍后通过查找表进行分派/访问。我正在为脚本系统添加对类派生层次结构的适当支持,并且我认为能够隔离这些接口的基类版本将有助于节省时间,并在向脚本解释器注册可用基类时使整个过程更清晰。还有其他方法可以实现这一点,例如为每个可用基类(例如this->Dog::CallFunction, this->Dog::SetMember, this->Dog::GetMember)的每个所需方法注册特定于类的函数指针。然而,我认为使用接口可以让我在需要的时候更容易地修改东西。

我希望所有这些都是有意义的。

谢谢!

您有一个Corgi对象。您可以:

  1. 通过对所有调用(例如ptr->Dog::draw();)使用Dog::限定符,将其视为无处不在的Dog对象。这将失去你的虚拟调度,并且几乎肯定不是你想从你的问题中读到的。

  2. 实际上从你的Corgi构造一个新的Dog对象。只需使用正常的static_cast就可以转换任何其他类型或让隐式转换接管(例如Corgi c; Dog d(c);)。

这些是可供您选择的选项。想要保留Corgi,但在任何地方都自动地假装它是Dog,这既不合理也不合法,所以语言没有提供它。

我首先要说你的设计看起来有问题。

然而,你可以显式地说明你想要调用层次结构中的哪个函数:

Corgi* corgi = new Corgi;
corgi->Dog::draw();

这将从Dog而不是从Corgi调用draw方法。(我希望我正确理解了你的问题)

Tomalak已经为您概述了两个主要的选择:

  • 使用限定呼叫,或者

  • 构建Dog作为CorgiDog副本。

除了这些,你还可以

  • 使用一个简单的包装

class LooksLikeDog
    : public Dog
{
private:
    Dog*  realObject_;
    LooksLikeDog( LooksLikeDog const& );                    // No such.
    LooksLikeDog& operator=( LooksLikeDog const& );         // No such.
public:
    LooksLikeDog( Dog& other )
        : realObject_( &other )
    {}
    // Just for exposition: not implementing this does the same.
    virtual void draw() override { Dog::draw(); }
    // Example of other method that may need to be implemented:
    virtual void bark() override { realObject_->bark(); }
};
但最好的解决方案最有可能是修复您的设计。: -)

实现Corgi绘制函数并调用父函数的实现:

virtual void Corgi::Draw() 
{ 
    Dog::draw(); 
}