0

I am trying to write a c++ abstract class and I can't figure out how to require implementers of this class to contain a static function.

For example:

class AbstractCoolThingDoer
{
    void dosomethingcool() = 0; // now if you implement this class 
                                        // you better do this
}

class CoolThingDoerUsingAlgorithmA: public AbstractCoolthingDoer
{
    void dosomethingcool()
    {
        //do something cool using Algorithm A
    }
}

class CoolThingDoerUsingAlgorithmB: public AbstractCoolthingDoer
{
    void dosomethingcool()
    {
        //do the same thing using Algorithm B
    }
}

Now I'd like to do the coolthing without the details of how coolthing gets done. So I'd like to do something like

AbstractCoolThingDoer:dosomethingcool();

without needing to know how the coolthing gets done, but this seems to require a function that is both virtual and static which is of course a contradiction.

The rationale is that CoolThingDoerUsingAlgorithmB may be written later and hopefully the softare that needs cool things done won't have to be rewritten.

EDIT:Not sure I was clear on what I'm trying to accomplish. I have 3 criteria that I'm looking to satisfy

  1. A library that uses abstractcoolthingdoer and does not need to be rewritten ever, even when another coolthingdoer is written that the library has never heard of.

  2. If you try to write a coolthingdoer that doesn't conform to the required structure, then the executable that uses the library won't compile.

  3. coolthingdoer has some static functions that are required.

I'm probably chasing down a poor design, so please point me to a better one. Am I needing a factory?

OldMcFartigan
  • 129
  • 1
  • 11
  • And how exactly would `CoolThingDoerUsingAlgorithmB`'s implementation be picked up? – juanchopanza Sep 09 '13 at 22:24
  • You're allowed to provide implementations for pure virtual functions. So provide an (out-of-line) implementation of `AbstractCoolThingDoer::dosomethingcool` and derived classes will still be forced to override the virtual function, but the ones that don't care to do the *cool thing* differently can still call the default base class implementation explicitly within their body. – Praetorian Sep 09 '13 at 22:31
  • probably in this case you may just define pointer to 'void dosomethingcool()' and declare it as member in AbstractCoolThingDoer? – vasylz Sep 09 '13 at 22:33
  • How do you plan on distinguishing which implementation of `dosomethingcool` should be called by `AbstractCoolThingDoer`? – agbinfo Sep 09 '13 at 22:56
  • @agbinfo I was thinking of having a template in there, with a dynamic_cast((B*)0) to enforce inheritance (will that work?) – OldMcFartigan Sep 09 '13 at 23:09
  • @user2762953 The usual idiom is `AbstractCoolThingDoer* doer = new CoolThingDoerUsingAlgorithmX();`. Then you can pass that to a function and that function doesn't have to know about the derived class. It can call `doer->dosomethingcool();` What part of that approach do you find a problem with? – agbinfo Sep 09 '13 at 23:17
  • @user2762953 The other thing you might be interested in is factories. You add a `getInstance()` method in `AbstractCoolThingDoer` and that method creates the derived class based on whatever is needed to decide which subclass you need. – agbinfo Sep 09 '13 at 23:21
  • i asked similar question http://stackoverflow.com/questions/3313754/static-abstract-methods-in-c – pm100 Sep 09 '13 at 23:35

2 Answers2

3

Maybe, something like this will help (see ideone.com example):

#include <iostream>

class A
{
 protected:
  virtual void do_thing_impl() = 0;
 public:
  virtual ~A(){}
  static void do_thing(A * _ptr){ _ptr->do_thing_impl(); }
};

class B : public A
{
 protected:
  void do_thing_impl(){ std::cout << "B impl" << std::endl; }
};

class C : public A
{
 protected:
  void do_thing_impl(){ std::cout << "C impl" << std::endl; }
};

int main() 
{
 B b_;
 C c_;

 A::do_thing(&b_);
 A::do_thing(&c_);  

 return (0);
}

EDIT: It seems to me the OP does not need run-time polymorphism, but rather compile-time polymorphism without need of class instance (use of static functions when the implementation is hidden in the derived classes, no instance required). Hope the code below helps to solve it (example on ideone.com):

#include <iostream>

template <typename Derived>
struct A
{
  static void do_thing() { Derived::do_thing(); }
};

struct B : public A<B>
{
  friend A<B>;
 protected:
  static void do_thing() { std::cout << "B impl" << std::endl; }
};

struct C : public A<C>
{
  friend A<C>;
 protected:
  static void do_thing() { std::cout << "C impl" << std::endl; }
};

int main() 
{
 A<B>::do_thing();
 A<C>::do_thing();

 return (0);
}

EDIT #2: To force fail at compile-time in case user does not adhere to desired pattern, here is the slight modification at ideone.com:

#include <iostream>

template <typename Derived>
struct A
{
  static void do_thing() { Derived::do_thing_impl(); }
};

struct B : public A<B>
{
  friend A<B>;
 protected:
  static void do_thing_impl() { std::cout << "B impl" << std::endl; }
};

struct C : public A<C>
{
  friend A<C>;
 protected:
  static void do_thing_impl() { std::cout << "C impl" << std::endl; }
};

struct D : public A<D>
{
 friend A<D>;
};

int main() 
{
 A<B>::do_thing();
 A<C>::do_thing();
 A<D>::do_thing(); // This will not compile.

 return (0);
}
lapk
  • 3,838
  • 1
  • 23
  • 28
  • And the obvious follow-up question to OP is, why make it a static in the first place? You need to act on an instance, so why not just have a plain old non-static member function? – juanchopanza Sep 09 '13 at 22:38
  • @juanchopanza I don't know exactly. Maybe the author of `class A` wants to do some common pre/past processing in `static` function? – lapk Sep 09 '13 at 22:49
  • I guess what you both are saying is that in general one needs to choose either 1) instantiate an object to call it's functions even when that isn't intuitive or 2) use something besides inheritance to ensure that addon classes have the required structure? – OldMcFartigan Sep 09 '13 at 22:50
  • @user2762953 It depends of what are you trying to achieve. It seems to me from your follow-up question that you don't need run-time polymorphism, but rather compile-time polymorphism. – lapk Sep 09 '13 at 22:55
  • @Petr Budnik Right. I need extensibility and in my (new to c++) mind I figure inheritance is the way to provide that while enforcing certain ground rules. But when i started putting pen to paper I started realizing that there are certain functions that "feel" static. That is didn't seem like they should require an instantiation of an object. So I don't know wether to instantiate dummy objects just to access their functions or take those functions outside objects. But then I don't know how to keep everything tidy. – OldMcFartigan Sep 09 '13 at 23:04
  • @user2762953 If functions _logically_ belong to a class, but do not require an instance, make them `static`, sure. Then, I suppose, you do not need virtual mechanism, because you don't need run-time polymorphism. The user of your library should know at compile-time a `static` function of which class they want to call at this point. – lapk Sep 09 '13 at 23:09
  • @PetrBudnik Yes, that's exactly what I needed. Thanks! I'd upvote but I don't have enough street cred. – OldMcFartigan Sep 09 '13 at 23:34
  • @user2762953 Glad I could help. Notice, it forces user to provide their version of `static do_thing()`. If you need to have a default fallback, you'll need to modify things slightly (by using some SFINAE, possibly)... You can also consider accepting the answer if it's satisfactory ;). – lapk Sep 09 '13 at 23:40
  • So if I tried to do A::do_thing() where D didn't have a do_thing method then wouldn't this still compile? How am I enforcing conformity to A's structure? – OldMcFartigan Sep 10 '13 at 14:54
  • @OldMcFartigan Yes, it will still compile but will enter endless recursion at run-time. If you want compilation to fail, you can use something like [this](http://ideone.com/TL72lM) (see the new edit too). – lapk Sep 10 '13 at 20:30
0

This looks to me like right place to implement bridge pattern. Maybe this is what you are (unconsciously) willing to achieve. In short you specify an interface and its implementations, then call to your do_thing method in turn calls an implementation on a pointer to implementer class.

C++ example

4pie0
  • 29,204
  • 9
  • 82
  • 118