简体   繁体   English

从模板派生类访问方法而无需在c ++中使用虚函数?

[英]Accessing a method from a templated derived class without using virtual functions in c++?

How do I get around this? 我该如何解决? I clearly cannot make the value() method virtual as I won't know what type it is beforehand, and may not know this when accessing the method from b: 我显然不能使value()方法虚拟化,因为我事先不知道它是什么类型,并且从b访问该方法时可能不知道这一点:

class Base
{
public:
    Base() { }
    virtual ~Base() { }
private:
    int m_anotherVariable;
};

template <typename T>
class Derived : public Base
{
public:
    Derived(T value) : m_value(value) { }
    ~Derived() { }

    T value() { return m_value; }
    void setValue(T value) { m_value = value; }
private:
    T m_value;
};

int main()
{
    Base* b = new Derived<int>(5);

    int v = b->value();

    return 0;
}

Compilation errors: 编译错误:

error: 'class Base' has no member named 'value'

This statement: 这个说法:

int v = b->value();

The variable 'b' is being trated like it is an object of Derived<int>. 变量'b'被当作Derived <int>的对象进行处理。
So tell the compiler: 因此,告诉编译器:

int v = dynamic_cast<Derived<int>*>(b)->value();

Note: If b is not a Derived<int> the result of the cast is NULL. 注意:如果b不是Derived <int>,则强制转换的结果为NULL。
So the following would probably be safer: 因此,以下内容可能会更安全:

Derived<int>*  d = dynamic_cast<Derived<int>*>(b);
if (d)
{
    int v = d->value();
}
else
{
    // Error
}

Alternatively by using references you get a bad_cast exception thrown: 或者,通过使用引用,您会抛出bad_cast异常:

// Throw bad_cast on failure.
Derived<int>& d = dynamic_cast<Derived<int>&>(*b);
int v = d->value();

Or to be nice and obscrure we can do it one line. 或者,要变得晦涩难懂,我们可以一行完成。

// Assign v or throw bad_cast exception:
int v = dynamic_cast<Derived<int>&>(*b).value();

But I think you can achieve what you are trying to do with the boost::any 但是我认为您可以通过boost :: any实现您想做的事情

int main()
{
    boost::any   b(5);

    int    v = boost::any_cast<int>(b);

    b        = 5.6; // double
    double d = boost::any_cast<double>(b);
}

I think there may be some problems with your design if you ask this question (from my experience, with my designs). 我认为,如果您问这个问题(根据我的经验和我的设计),您的设计可能会有一些问题。
However, there are some workarounds: 但是,有一些解决方法:

  1. As other people already answered, you can make Base a class template. 正如其他人已经回答的那样,您可以将Base设为类模板。
  2. You can downcast b (although I prefer to avoid downcasts if I can) 您可以垂头丧气b(尽管我更愿意避免垂头丧气)
  3. You can declare value() as returning boost::any in Base and make it pure virtual 您可以在Base中将value()声明为返回boost :: any并将其设为纯虚拟
  4. You can even declare it as returning void* (but don't do that. It's an option, but a bad one) 您甚至可以将其声明为返回void *(但不要这样做。这是一个选择,但很糟糕)

But the real question here is what do you try to describe here? 但是,这里真正的问题是您试图在这里描述什么? What is the meaning of Base, Derived and value(). Base,Derived和value()的含义是什么。 Ask yourself these question and you may not need these answers... 问自己这些问题,您可能不需要这些答案...

Some solution: 一些解决方案:

template < typename T>
class Base{
public: 
    Base() { }    
    virtual ~Base() { }
    virtual T value() = 0;
private:    
    int m_anotherVariable;
};

template <typename T>
class Derived : public Base<T> {
  ...
}

int main(){    
    Base<int>* b = new Derived<int>(5);    
    int v = b->value();    
    return 0;
}

Another solution: 另一个解决方案:

class Base {
public: 
    Base() { }    
    virtual ~Base() { }
    template<class T> T value() const;
private:    
    int m_anotherVariable;
};

template <typename T>
class Base2 : public Base {
public: 
    Base2() { }    
    virtual ~Base2() { }
    virtual T getValue() const = 0;    
};

template<class T> T Base::value() const {
    const Base2<T> * d = dynamic_cast<const Base2<T> *>(this);
    return d ? d->getvalue() : T();
}

template <typename T>
class Derived : public Base2<T> {
public:    
    Derived(T value) : m_value(value) { }    
    virtual ~Derived() { }    
    void setValue(T value) { m_value = value; }
    virtual T getValue() const { return  m_value; }    
private:    
     T m_value;
}

int main(){    
    Base* b = new Derived<int>(5);    
    int v = b->value<int>();
    return 0;
}

In this case Base will need to know about the template type so b->value returns a T. 在这种情况下,Base需要了解模板类型,因此b-> value返回T。

I would suggest adding the template to Base and then make value a virtual function on Base 我建议将模板添加到Base,然后在Base上使值成为虚拟函数

You could cast your pointer to Derived : 您可以将指针投射到Derived

int v = dynamic_cast<Derived<int>*>(b)->value();

Of course in real code, you have to add checking to make sure that dynamic_cast didn't fail. 当然,在实际代码中,您必须添加检查以确保dynamic_cast不会失败。

Why don't make Base template-based class too? 为什么也不要使基于Base模板的类呢? Then you can have value as a virtual member. 然后,您可以作为虚拟成员而有价值。

Or you can downcast b to Derived. 或者,您可以将b降为Derived。

It looks like you want dynamic polymorphism but using only the "static polymorphism" of templates. 看起来您想要动态多态性,但仅使用模板的“静态多态性”。

If you want dynamic polymorphism you do need virtual members in your base class ( along with your virtual destructor ) or the down_cast if you do not have a common interface. 如果要动态多态性,则确实需要基类中的虚拟成员(以及虚拟析构函数),或者如果没有通用接口,则需要down_cast。

If not, remove the virtual destructor and use only pointers to or instances of derived types. 如果没有,请删除虚拟析构函数,并仅使用指向派生类型的指针或实例。

About Base as a template : 关于Base作为模板:

It will prevent you from having a single base class for dynamic polymorphism as Base< int > and Base< other > will be incompatibles. 它会阻止您为动态多态性使用单个基类,因为Base <int>与Base <other>是不兼容的。

One way of handling this is via the visitor pattern . 处理此问题的一种方法是通过访客模式 The basic idea is that in your hierarchy of classes you implement an onNode function that accepts a visitor. 基本思想是,在类的层次结构中,您将实现一个接受访问者的onNode函数。 Then, you write specific visitors that do what you want. 然后,您编写特定的访问者来执行您想要的操作。 In your case, you'd end up with: 就您而言,您将得到:

class GetIntValue : public BaseVisitor
{
public:
  GetIntValue (int & result)
  : m_result (result) {}

  void onNode (Derived<int> & d)
  {
    m_result = d.m_value;
  }
  void onNode (Derived<A> & d)
  {
    assert (! "calling GetIntValue on a node that doesn't have a value");
  }


private:
  int & m_result;
};

int main()
{
  Base* b = new Derived<int>(5);

  int v;
  GetIntValue(v).visit (*b);

  return 0;
}

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

相关问题 在运行时从没有虚拟函数的基类方法访问派生类方法 - Accessing derived class method from base class method without virtual functions on run time 在从模板化基类派生的类中使用虚拟方法 - Using virtual methods in class derived from templated base class 无需类型转换的模板化派生类的C ++访问成员 - C++ access member of templated derived class without typecast C ++虚拟模板化方法 - C++ virtual templated method 为什么我不能从C ++中的派生类实例调用模板化方法? - Why can't I call a templated method from a derived class instance in C++? C ++:使用抽象类中的指针来访问派生类的方法; 派生类apears也是抽象的 - C++: Use pointer from abstract class for accessing method of derived classes; derived class apears to be abstract as well 如何使用来自 C++ 中基本方法的不同输入集的派生函数的虚函数? - How to use virtual functions of derived functions with different set of inputs from a base method in C++? C ++继承从基类指针访问派生类中的非虚函数 - C++ Inheritance accessing a non-virtual function in derived class from base class pointer 访问 C++ 中派生的 class 的模板参数的虚拟成员 function - Accessing a virtual member function of a template argument derived class in C++ 具有类派生类的基类纯虚函数 - Base class pure virtual functions with templated derived class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM