7

In some C++ code, I use integers to store lots of changing data. To analyze my program, I want to log certain changes to some of the variables, such as how often a certain value is assigned to, and how often that assignment is redundant (the new value is the same as the old value.)

If the type were a class Foo, I'd just derive a new LoggingFoo and add my logging data to the member function(s) I was interested in, and then call the parent member function. I'd have to update my code to use the new type, but as long as I was originally consistent with typedefs, that's a one-line change.

My problem is that the variable I want to add logging to is an int. You can't derive from built in types in C++ (can you?)

My question is whether there's a clever way to derive from the basic types (int, float, double, etc).

The solution may be to define a new class that effectively is an int.. it defines every operation an int can do and just applies that operation to a private int data member. This strategy will work, but perhaps others have already made such a class and I can just use a "fakeint.h" header file definition. Is there such a "proxy native class wrapper" type definitions already available somewhere before I implement them myself?

I do realize of course my proxy int can't be used interchangably with an int especially since existing function definitions all expect an int.. but for my app, this is all in an inner loop which is doing lots of simple native +-*^= operations, not used as function arguments or anything.

SPWorley
  • 11,550
  • 9
  • 43
  • 63
  • 1
    you should look into boost's operators: http://www.boost.org/doc/libs/1_39_0/libs/utility/operators.htm. It'll let you create a class which has all of the typical operators to make it act like a native integer type. – Evan Teran Jul 26 '09 at 02:18
  • @Evan.. thanks, that's a nice resource in general! Overkill for what I need but if I do need to roll my own it'd cut the redundant work significantly. – SPWorley Jul 26 '09 at 02:21

4 Answers4

9

You can't derive a class from int, but you should be able to make a class (e.g. Integer) that is interchangeable with int by implementing Coplein's Concrete Data Type idiom from Advanced C++: Programming Styles and Idioms and then by overloading the type cast operator from Integer to int and defining a conversion operator from int to Integer.

here is another link that describes the basic Idioms from the book

and yet another link that I think is pretty close to what you are looking for http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Int-To-Type

Jeff Leonard
  • 3,284
  • 7
  • 29
  • 27
8

Something like this...

template <typename T> class logging_type
{
private:
   T value;
public:
   logging_type() { }
   logging_type (T v) : value(v) { }  // allow myClass = T
   operator T () { return value; }  // allow T = myClass
   // Add any operators you need here.
};

This will create a template class that's convertible to the original type in both directions. You'd need to add logging handling and overload operators for every operation used on that type in your code.

This still might not be quite what you want, because it's implicitly convertible to int (or whatever type you specify), so your code might silently convert your logging int to an int and you'd be left with incomplete logs. You can prevent this in one direction by adding an 'explicit' keyword to the constructor, but you can't do anything similar with the conversion operator. Unless you perhaps make it private... I haven't tried. Doing either of those things will somewhat defeat the purpose though.

Edit: Since c++11, you can add explicit to conversion operators.

Stijn Frishert
  • 1,543
  • 1
  • 11
  • 32
Dan Olson
  • 22,849
  • 4
  • 42
  • 56
  • 2
    This feels very very promising.. it has the appeal that everything works by default, and the only funcs I need to wrap are the ones I want to deal with custom logging. It **almost** works! i=i+1; is OK. cout << i; is OK. But for example i+=1; or i++; does not. Still, this may work well for filling in most of the operators and I can manually deal with the remainder. – SPWorley Jul 26 '09 at 03:02
3

This is actually one case where #define is very helpful. I recommend

#ifdef DEBUG
#    define INTGR MyDebugIntegerClass
#else
#    define INTGR int
#endif

Make sure that MyDebugIntegerClass can cast itself to a regular int, and has all appropriate operators. Then, write your code with INTGR.

In debug mode, you'll get all the logging of your class, but in release mode, you'll get a plain-basic int.

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • 2
    Yeah, I have typedefs already so it's even easier. My main question is efficiently building a MyDebugIntegerClass without having to manually wrap 50+ native int operators. (Or just find someone who has already done it.) – SPWorley Jul 26 '09 at 03:04
-1

you can never derive from primitive types

Erix
  • 7,059
  • 2
  • 35
  • 61