2015-10-14 26 views
3

假设我有纯类A和类B,C,D等衍生自A。是否有可能从A的析构函数中知道哪个派生类正在被销毁?当使用CRTP是否有可能在C++中基类销毁期间知道派生实例类型?

+1

我想你的意思是自动的,就是编译器会告诉你吗? “手动”解决方案是添加一些数据成员,其中存储了派生最多的类型,例如一个'type_info const&'。 – dyp

+2

不会。至此所有衍生部分都消失了。你为什么需要这个? –

+0

我想知道如果你能达到相同的目的,将基本析构函数标记为虚拟并覆盖每个派生类中的析构函数 – Jimmy

回答

3

可以做,像这样:

template <typename TDerived> 
class Base {}; 

class Derived : public Base<Derived> {}; 

然后Base知道在任何时候都派生类型。

4

这取决于你需要什么。当然,人们会质疑为什么,这是一个值得怀疑的愿望。

在编译时不可能在任何时候自动从基类中知道对象的动态类型。如果你想知道编译时的类型,唯一的解决方案是将这些信息包含在基本类型本身中,这基本上就是CRTP模式。例如:

class BaseBase { 
    // body 
}; 

template <typename D> 
class Base : BaseBase { 
    //body 
}; 

class Derived1 : public Base<Derived1> { 
    // body 
}; 

class Derived2 : public Base<Derived2> { 
    // body 
}; 

这样的Base的析构函数将在编译时“知道”的派生类在编译时的类型。然而,这具有的缺点是,公共超级类型Derived1Derived2不是Base,但BaseBaseBaseBase析构函数不知道(你可能会回到原点)。

如果你只想知道在运行时(这意味着你不能直接做的事情一样DerivedClass::something)例如用于调试的原因,你可以在基类中添加一个成员包含类型信息:

class Base { 
protected: 
    type_info const* type; 

public: 
    Base() { 
     type = &typeid(this); 
    } 
}; 

class Derived : public Base { 
public: 
    Derived() { 
      type = &typeid(this); 
    } 
}; 

请注意,这取决于Base构造函数将在构造函数Derived之前运行,所以type指针将引用当前已构造的派生类。

+0

你忘了在第二个例子中继承'Base' –

0

CRTP的问题在于,您有不同的基本类型,您不能将其用于动态多态性。

如果您不需要派生对象的实际类型,但想要根据它执行代码,则存在不同的可能性。请注意,您不能在析构函数中调用任何虚函数。但是,您可以:

1.添加一个类型成员变量(例如std::type_info,枚举或其他)并手动调度。

2.使用一种技术作为virtual constructor idiom的对应方法,在明确销毁之前调用函数(通过delete或类似方法)。然而,这可以被遗忘,或者(如果被强制执行)严重限制了你如何销毁物体。

3。您可以使用策略模式:

class Base 
{ 
    struct Strategy 
    { 
     virtual ~Strategy(); 
     virtual void onDestroy() = 0; 
    } 

    std::unique_ptr<Strategy> strategy; 

public: 
    explicit Base(std::unique_ptr<Strategy> strategy) 
    : strategy(std::move(strategy)) 
    { 
    } 

    virtual ~Base() 
    { 
     strategy->onDestroy(); 
    } 
}; 

class Derived1 : public Base 
{ 
    struct Strategy1 : Strategy 
    { 
     virtual void onDestroy() { ... } 
    }; 

public: 
    Derived1() 
    : Base(std::make_unique<Strategy1>()) 
    { 
    } 
}; 

注意与C++ 11个函数对象,这成为相当简单:

class Base 
{ 
    std::function<void()> strategy; 

public: 
    explicit Base(std::function<void()> strategy) 
    : strategy(std::move(strategy)) 
    { 
    } 

    virtual ~Base() 
    { 
     strategy(); 
    } 
}; 

class Derived1 : public Base 
{ 
public: 
    Derived1() 
    : Base([]() { ... }) 
    { 
    } 
}; 

重要:你必须确保该策略对象或函数对象不会引用派生类的任何成员,因为派生对象在调用时已被销毁。如果你需要访问成员属性,你最好直接重新定义析构函数。

相关问题