1

I have a class, and let's called it class myClass

class myClass{

  // some math operations
  myClass get_difference(myClass &b)
  {
       print_operation(*this, b);
       do_something else
       return...
  }
  myClass get_sum(myClass &b)

// pseudocode 
void print_operation(const myClass *a, const myClass &b)
{
     if function == get_sum
         print a << "plus" << b;
     if function == get_difference
         print a << "minus" << b;
}

  // overload cout as well
};

Suppose I called the following

myClass anObject(1,2);
myClass anotherObject(3,4);

anObject.get_sum(anotherObject);
anObject.get_difference(anotherObject);

get_sum / get_difference will call print_operation, but I want to be able to determine the caller so a different output format is used.

Naive approach: Use switch-case Add a new parameter called "id". Give each function (the caller) an id, and use switch-case statements in print_operation.

However, is there an alternative? A more elegant solution?

Thanks.

CppLearner
  • 16,273
  • 32
  • 108
  • 163
  • More elegant - no. Alternative - a template. Hack - use stack trace (platform dependent). –  Dec 19 '11 at 03:02
  • 3
    That's not a naive approach, that's the *right* approach: pass in some sort of parameter that `print_operation` can use to do the right thing. Functions should not know, nor care, who/what called them, just that they were called and given those parameters. – Andrew Marshall Dec 19 '11 at 03:06
  • Hahah. Thanks. I wouldn't know. There is always someone who can come up with a smarter way. Suggestions from below are very useful, however. I got you. :) The important thing: "functions should not know, nor care who/what called them." – CppLearner Dec 19 '11 at 18:58

3 Answers3

2

Cpp functions don't know who is the caller unless you hack the stack, which is, kind of, complicated. So, generally speaking, you have to pass the information(in function parameter, template parameter, data member..) to print_operation to tell it what operation to print.

So the answer is no more elegant solution.

zchenah
  • 2,060
  • 16
  • 30
  • Hi. Thank you for the response. Yeah. But at this stage I'd stick with the simple switch-case solution. Rewriting my class with template, etc is a mess right now :) Thanks. – CppLearner Dec 19 '11 at 18:56
2

Have you considered adding a virtual const std::string& getFormatted() const in the caller?

If the format will be a function of both arguments to your operator, you would have to create some kind of table of combinations to look up your format.

If the format is only a function of the length of the printing of each argument (much simpler), you could use virtual size_t getFormatLength() const.

Note: print_operation() doesn't know anything about the caller, except that it has a getFormatted() function, yet the caller gets to format itself based on the value of op.

This is OOP/polymorphism at work.

As Andrew Marshall answered in his comment above, part of OOP/encapsulation is, you should not know anything about the implementation of the caller.

Polymorphism, done right, should try to encapsulate the implementation details away from the caller.

class myClass
{
  public:
    virtual std::string getFormatted( const std::string& op ) const = 0;
};

class A : public myClass
{
  public:
    virtual std::string getFormatted( const std::string& op ) const
    {
      // switch on the value of op or the length of op, etc...

      return std::string( "this, formatted according to class A specs and op" );
    }
};

class B : public myClass
{
  public:
    virtual std::string getFormatted( const std::string& op ) const
    {
      // switch on the value of op or the length of op, etc...

      return std::string( "this, formatted according to class B specs and op" );
    }
};

void print_operation(const myClass &a, const myClass &b )
{
  std::string op;

  if ( function == get_sum ) {
    op = "plus";
  } else if ( function == get_difference ) {
    op = "minus"; 
  }
  std::cout << a.getFormatted( op ) << op << b.getFormatted( op );
}
kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • I am not sure if I understand what getFormat do? Mind to expand on that a bit? Thanks! – CppLearner Dec 19 '11 at 18:57
  • 1
    @CppLearner it gives your particular instance of myClass a chance to specify what the format should look like, because the implementation will live in a subclass of myClass. When you say "but I want to be able to determine the caller so a different output format is used", having a virtual getFormat() will give the caller a chance to specify the output format. – kfmfe04 Dec 19 '11 at 19:12
  • Thanks kfmfe04 I was going to ask if you were referring to inheritance and poly. Thanks. It really helps. – CppLearner Dec 20 '11 at 02:17
  • @CppLearner - ty for the feedback - good luck with your adventures in C++! – kfmfe04 Dec 20 '11 at 02:46
1

I don't think the problem boils down to knowing who the caller is. It sounds like you really want to define different ways to format the data and there may be different desired formatters for different callers.

Taking a lesson from .NET, you might consider a design where you have a format string to define how to output the data such as in IFormattable.ToString. In that example, a format string is used to differentiate different output formats. In your case, you could define it with an integer, an enum, or whatever is appropriate.

bobbymcr
  • 23,769
  • 3
  • 56
  • 67