Avoiding dynamic_cast in implementing virtual functions in a derived class

Here is an example code explaining what I'm trying to achieve.

Basically, I have an algorithm that depends on some basic operations available in the class. I defined these operations in a pure abstract base class. I want to apply this algorithm to a variety of objects that provide these operations by calling classes for specific objects.

However, different derived objects are incompatible with each other as far as these operations are concerned. My question is, can I avoid using RTTI to make sure, for example, bool deriv2 :: identity (const base * other2) asserts (or another output mechanism), where other2 is not of type output2.

An alternative could be a template function algorithm on a specific derived object, but this would mean that its implementation would have to live in a header file, which I do not want to do with 1) Changing the algorithm code for a test purpose can lead to recompilation of large parts of the code. 2) The implementation of the algorithm will be shown in the header instead of living well in the source file, hidden from the end user.

Header file

#include <list>

class base
{
public:
 virtual float difference(const base*) const = 0;
 virtual bool identical(const base*) const = 0; 
};


class derived1 : public base
{
 public:
 float difference(const base* other1) const
 {
  // other1 has to be of type derived1
            if(typeid(other1) == typeid(this))
            {
                    // process ...
            }
            else
            {
                    assert(0);
            }
  return 1;
 }

 bool identical(const base* other1) const
 {
  // other1 has to be of type derived1
            if(typeid(other1) == typeid(this))
            {
                    // compare...
            }
            else
            {
                    assert(0);
            }
  return true;
 }
};


class derived2 : public base
{
 public:
        float difference(const base* other2) const
        { 
             // process ...
  // other2 has to be of type derived2
            return 2;
        }

 bool identical(const base* other2) const
        {
                // do comparison
  // derived1 and derived2 cannot be compared
                return true;
        }
};

// Declaration
int algorithm(std::list<base*>& members);

Algorithm Implementation Source File

#include "header_file_containing_base"
int algorithm(std::list<base*>& members)
{
 // This function only relies on the interface defined in base
 // process members;

 return 1;
}

Main program

int main()
{
  // Create lists of derived1 and derived2
  // Run algorithm on these lists
}
+3
source share
3 answers
+2
source

, : .

  • enum, . , .
  • A Factory ( )
  • ...

Factory id:

class IdFactory
{
public:
  template <class T>
  static size_t GetId(T const&) // argument deduction
  {
    static size_t const Id = GetIdImpl();
    return Id;
  }

private:
  static size_t GetIdImpl()
  {
    static size_t Id = 0;
    return ++Id;
  }
}; // class IdFactory

:

class Base
{
public:
  explicit Base(size_t id): mId(id) {}
  size_t const mId; // meaningless to change it afterward...

private:
};

class Derived: public Base
{
public:
  explicit Derived(): Base(IdFactory::GetId(*this)) {}
};

mId . , const, ... const getter...

float Derived::difference(const Base& rhs)
{
  assert( IdFactory::GetId(*this) == rhs.mId );

  // ...
}

:

  • GetId ,
  • GetId , - , static : if, true ( ).
  • == ;)

, , .

-, :

class Other: public Base
{
public:
  virtual size_t id() const { return IdFactory::GetId(*this); }
};

, const , .

+1

. , . - .

0
source

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


All Articles