繁体   English   中英

有没有办法在超类构造函数中知道调用对象的子类? C++

[英]Is there a way to know in the superclass constructor the subclass of the calling object? C++

假设我有类似的东西:

class A 
{
  public:
     A(A* owner)
     {
        m_owner=owner;
        if (dynamic_cast<B*>(this))
        {
          m_id=sm_bid; 
          sm_bid++;
        }
        else
        {
          m_id=sm_aid;
          sm_aid++;
        }
     }
  private:
    int m_id;
    A*  m_owner;
    static int sm_aid;
    static int sm_bid;
};

A::sm_aid=0;
A::sm_bid=0;

class B: public A
{
    B(A* owner) : A(owner) {}
};

不幸的是,dynamic_cast 无法捕捉到它是一个 B 对象(实例化时)。 这听起来合乎逻辑(因为之前调用了超类中的构造函数来调用子类中的构造函数。有没有办法实现这样的功能?

您的设计看起来很复杂,几乎可以肯定可以在不需要知道它是派生的情况下实现。

但是,用 C++ 打自己的脚是神圣的权利 :) 因此,您可以尝试使用Curiously Recurring Template Pattern (CRTP)来实现您的目标(通过静态多态在构造函数中实现多态行为)。

这是快速而肮脏的草图

#include <iostream>
#include <type_traits>

struct Owner
{};

struct B;

template <class Derived>
struct A : public Owner
{
    A(Owner*)
    {
        if (std::is_same<Derived, B>::value)
            std::cout << "called from derived B" << std::endl;
        else
            std::cout << "not called from derived B\n" << std::endl;
    }
};

struct B : public A<B>
{
    B(Owner* owner) : A<B>(owner) {}
};

int main()
{
    A<void> a(nullptr);
    B b(&a);
}

输出:

not called from derived B
called from derived B

注意:我注意到您正在使用静态变量进行计数。 请注意,每个模板实例化都有自己的静态变量!

首先, dynamic_cast工作,您需要在基类中至少有一个虚拟方法(通常析构函数是虚拟的,因为您经常出于其他原因需要它)。

其次,在构造A子对象时,在A的构造函数中,所有虚函数都将引用A的类定义(即使您实际上A构造为B的子对象),并且dynamic_cast会说this不是类型B

这是因为在B构造函数完成之前,该对象不是类型B的对象,因此任何和所有尝试确定它是否是类型B都会说这不是因为该对象实际上不是类型B (然而)。

我希望这可以为您解决一些困惑。

编辑:
我刚刚注意到你问题下的最后一段,你在那里寻求解决方案。

如果不了解有关问题的更多信息,将很难真正帮助您实现此功能。 我的建议是不要这样做,也许完全使用另一个类来为您的对象分配 id,而不是尝试让A这样做。

如果它真的必须在A那么这可能会有所帮助:

struct A
{
  template <class FinalType>
  A(A* owner, FinalType *){...}//use std::is_same to check if `B` or not
};

struct B : A
{
  B(A * owner):A(owner, this){}
};

如果A是抽象类型,则可以使用基于标签的重载技术。

class B;
class C;

class A
{
public:
    template<class Derived>
    struct my_derived
    {
        using type = Derived;
    };

protected:
    explicit A(my_derived<B>)
    {
        // Do whatever you want when derived is B
    }

    explicit A(my_derived<C>)
    {
        // Do whatever you want when derived is C
    }

private:

};

class B : A
{
public:
    B() : A(A::my_derived<B>())
    {
    }
};

class C : A
{
public:
    C() : A(A::my_derived<C>())
    {
    }
};

另一种方法是 AMA 建议的基于模板的编程。 但是尽管模板是 C++ 中的强大功能,但它们也有自己的问题。 它们不能在 cpp 文件中实现。 它们会导致代码膨胀,从而影响性能,因为更大的代码大小会导致更高的指令缓存未命中率。

所以我认为这种方法比RTTI更好, RTTI会影响运行时性能,并且您必须在基类中声明一个虚拟函数,以及基于模板的方法。

看起来这很好用:

#include <iostream>
#include <type_traits>

class Owner
{};

class B;

template <class Derived>
class A : public Owner
{
    public:
    A(Owner* owner)
    {
        m_owner=owner;
        if (std::is_same<Derived, B>::value)
            std::cout << "called from derived B" << std::endl;
        else
            std::cout << "not called from derived B\n" << std::endl;
    }
    private:
    Owner* m_owner;
};

class B : public A<B>
{
    public:
    B(Owner* owner) : A<B>(owner)
    {}
};

int main()
{
    A<void> a(nullptr);
    B b(&a);
}

向 AMA 致敬。 任何事情都可以在 C++ 中完成

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM