Accessing a method from a template derived class without using virtual functions in C ++?

How do I get around this? I obviously cannot make the value () method virtual, because I will not know what type it is in advance, and may not know this when accessing the method from 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'
0
source share
8 answers

This statement:

int v = b->value();

The variable "b" is passed, like the Derived <int> object.
So tell the compiler:

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

Note. If b is not a <int> derivative, the result of the cast is NULL.
Therefore, it would probably be safer:

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

, , bad_cast:

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

, , .

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

, , 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);
}
+3

, , ( , ).
:

  • , .
  • downcast b ( downcasts, )
  • value() boost:: any Base
  • void * ( . , )

- ? Base, Derived value(). , ...

+2

:

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;
}

:

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;
}
+1

Base , b- > value T.

Base Base

0

Derived:

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

, , , dynamic_cast .

0

? .

b Derived.

0

, , " " .

, ( ) down_cast, .

, .

:

Base <int> Base < > .

0

One way to deal with this is through a template. The basic idea is that in your class hierarchy you implement a function onNodethat accepts a visitor. Then you write specific visitors who do what you want. In your case, you will receive:

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;
}
0
source

Source: https://habr.com/ru/post/1720266/


All Articles