简体   繁体   English

如何从纯虚拟基类函数访问派生成员?

[英]How can I access to derived members from a pure virtual base class function?

I want to have a Collider interface class in which will have a overloaded -> operator to have access directy to the BoxCollider derived class.我想要一个 Collider 接口类,其中将有一个重载 -> 运算符来直接访问 BoxCollider 派生类。 I want to have access to the members of box collider through the interface and chnage the type of collider at run-time.我想通过界面访问 box collider 的成员并在运行时更改对撞机的类型。 So I thought of using templates:所以我想到了使用模板:

template<typename T>
class ColliderV2 {
public:
    virtual T* operator ->() = 0;
};

class BoxColliderV2 : public ColliderV2<BoxColliderV2> {
public:
    float width;
    float height;

    BoxColliderV2* operator ->() {
        return this;
    }


};
int main()
{
    ColliderV2<BoxColliderV2>* col = new BoxColliderV2;
    (*col)->width = 1; 

}

This works.这有效。 But templates , as far as I know, will generate a brand new Collider class in compile-time filling T with Box Collider, correct?但是模板,据我所知,会在编译时用 Box Collider 填充 T 生成一个全新的 Collider 类,对吗? Thats why it worked.这就是它起作用的原因。 But later it prevents me from changing the collider type.但后来它阻止我更改对撞机类型。 I also thought of just making a virtual Collider class with Collider* operator->() ;我还想过用Collider* operator->() ;制作一个虚拟的 Collider 类Collider* operator->() ; overload in the derived class BoxCollider* operator->() ;派生类BoxCollider* operator->() ;中的重载BoxCollider* operator->() ;

But if I tried :但如果我尝试:

Collider<BoxCollider>* col = new BoxCollider;
(*col)->width = 1; // won't work

doesn't work since Collider is not BoxCollider.不起作用,因为 Collider 不是 BoxCollider。 And I don't want to dynamic_cast every possible collider type I could have.而且我不想动态投射我可以拥有的所有可能的碰撞器类型。 So, what can be done here?那么,在这里可以做什么?

As you've already found out, this doesn't work.正如您已经发现的那样,这是行不通的。 Templates and runtime behavior are kind of contradicting mechanics.模板和运行时行为是一种相互矛盾的机制。 You can't create a common base class and let it act like a generic pointer to give you access to its derived types' members.你不能创建一个公共基类并让它像一个泛型指针一样让你访问它的派生类型的成员。

An interface specifies a contract against which you can code.接口指定您可以编码的契约。 You don't code against a specific implementation but the interface, so the interface has to provide all the members that you'd like to access.您不是针对特定实现而是针对接口进行编码,因此接口必须提供您想要访问的所有成员。 In your case this would result in width and height beeing part of ColliderV2 instead of BoxColliderV2 .在您的情况下,这将导致widthheight成为ColliderV2而不是BoxColliderV2 However this defeates the logic you are trying to mimic.然而,这打败了你试图模仿的逻辑。

There are a few approaches that you can take:您可以采用以下几种方法:

  1. Either make your collider type a variant, like要么使您的对撞机类型成为变体,例如

    using ColliderType = std::variant<BoxColliderV2, MyOtherCollider, ...>;

    and check for the actual type when you want to access the member并在您要访问成员时检查实际类型

    ColliderType myCollider = /* generate */; if (auto boxCollider = std::get_if<BoxColliderV2>(&myCollider); boxCollider) boxCollider->width = 0;
  2. Or, keep the base class that you have, remove the operator-> and the template and do a dynamic cast on it:或者,保留您拥有的基类,删除operator->和模板并对其进行动态转换:

     ColliderV2* col = new BoxColliderV2; if (auto boxCollider = dynamic_cast<BoxColliderV2*>(col); boxCollider) boxCollider->width = 0;
  3. You can also hide details like width or height behind more generic functions that are part of the interface.您还可以将widthheight等细节隐藏在属于界面一部分的更通用的功能后面。 For example:例如:

     class ColliderV2 { public: virtual void setBounds(float width, float height) = 0; }; class BoxColliderV2 : public ColliderV2 { public: void setBounds(float width, float height) override { this->width = width; this->height = height; } private: float width; float height; }; int main() { ColliderV2* col = new BoxColliderV2; col->setBounds(1, 1); }

I think you are approaching the problem from the wrong direction.我认为您从错误的方向解决问题。 The purpose of an interface is that you don't have to know about the exact type or the implementation.接口的目的是您不必知道确切的类型或实现。

For example: You are using Axis-Aligned Bounding Boxes for collision detection.例如:您正在使用轴对齐边界框进行碰撞检测。 So, even if your CircleCollider uses a radius , you are still able to calculate its width and height from it.因此,即使您的CircleCollider使用radius ,您仍然可以从中计算其widthheight Now, you don't have to worry about if you are dealing with a BoxCollider or a CircleCollider , you have everything to make a Bounding Box.现在,您不必担心处理的是BoxCollider还是CircleCollider ,您拥有制作边界框的一切。

class Collider
{
public:
    virtual float x() const = 0;
    virtual float y() const = 0;
    virtual float width() const = 0;
    virtual float height() const = 0;
};

class BoxCollider : public Collider
{
    // Implementation...
};

class CircleCollider : public Collider
{
    // Implementation...
};

Of course, you are maybe using something else, and not AABBs.当然,您可能正在使用其他东西,而不是 AABB。 I just wanted to demonstrate how you can use interfaces effectively.我只是想演示如何有效地使用接口。

What you are trying to do is discouraged by C++. C++ 不鼓励您尝试做的事情。 What you are trying to do is to change the type of something based on the return value of a function.您要做的是根据函数的返回值更改某些内容的类型。 The type system is designed to stop you from writing code like this.类型系统旨在阻止您编写这样的代码。
One important restriction of a function is that can only return one type-of-thing.函数的一个重要限制是只能返回一种类型的事物。 You can return one of a list of things if you wrap those possibilities in a class, and return that.如果将这些可能性包装在一个类中,则可以返回一系列事物中的一个,然后返回它。 In C++17, a ready-made class for this is std::variant .在 C++17 中,一个现成的类是std::variant The restriction on this is that the list of things must be fixed (or a closed-set).对此的限制是事物列表必须是固定的(或封闭集)。 If you want an arbitrary set of return values (open-set), you must use a different approach.如果您想要一组任意的返回值(开放集),您必须使用不同的方法。 You must restate your problem in terms a function that is done on the return value.您必须用在返回值上完成的函数来重申您的问题。

class BoxColliderV2 : public MyBaseCollider {
public:
    void SetWidth(float new_width) override; 
};

You may find this video useful.您可能会发现此视频很有用。 The bit of interest starts at around 40 minutes (but watch the whole video if you can).感兴趣的部分从大约 40 分钟开始(但如果可以,请观看整个视频)。 If you are interested in advice, I would suggest starting with std::variant , and if it works, move to virtual functions.如果您对建议感兴趣,我建议从std::variant 开始,如果有效,请转向虚函数。 Problems like collision detection get really complicated really quickly, and you will almost certainly require double dispatch at some stage.诸如碰撞检测之类的问题很快就会变得非常复杂,并且您几乎肯定会在某个阶段需要双重调度 Start simple, because it's only going to get more complicated.从简单开始,因为它只会变得更复杂。

These excerpts from the ISO-Guidelines may help ISO 指南的这些摘录可能会有所帮助
1. When you change the semantic meaning of an operator, you make it harder for other programmers to understand you code. 1. 当你改变一个操作符的语义时,你会让其他程序员更难理解你的代码。 guideline . 指南
2. Dynamic casting is verbose and ugly, but deliberately so, because dynamic casting is dangerous, and should stand out. 2.动态转换冗长丑陋,但有意如此,因为动态转换很危险,应该脱颖而出。 guideline 指南

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在基类中访问派生类的纯虚拟实现? - How to access derived class pure virtual implementation in base class? 我可以从派生类中的静态函数访问基类受保护的成员吗? - Can I access a base classes protected members from a static function in a derived class? 如果在两个以上的派生类中定义了纯虚函数,该如何从基类调用纯虚函数 - how to call pure virtual function from base class if that function is defined in more than 2 derived class 从纯虚类(A)派生的指针无法访问纯类(B)的重载方法 - Pointer derived from pure virtual class(A) can't access overload method from the pure class (B) 在派生类对象作为参数的基类中声明纯虚函数 - Declaring pure virtual function in base class with derived class object as arguments 在派生类中实现虚拟功能时访问基类私有成员 - Access Base Class private members when implementing virtual function in derived class 从基础 class 访问派生虚拟 function,好的做法? - Access derived virtual function from base class, good practice? 无法访问派生类中的基类保护成员! (在虚函数中) - Not able to access base protected members in derived class ! ( in virtual functions ) 我如何从另一个类的基类访问派生类中的受保护成员 - How can i acces protected members in a derived class from a base class that is firend of another class 允许派生类实现基本抽象类中的单个纯虚函数 - Allow derived class to implement a single pure virtual function from base abstract class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM