C++ style tips

Modular architecture

It is a very good thing to make a modular architecture. It permits creating several implementation for one functionnality (several ways to do it), and to easily switch from one to the other, or change a part of the program.

Inheritance

The most obvious way to do that is inheritance. You create an interface, which defines what your implementation must be able to do, and you inheritate several implementations that do it with different ways. Then anywhere else you always use the interface class, and it will use the implementation you initialized with, no matter what it is.

Let's take the example of a class that must tell if a pixel belongs or not to a category of colors :

class ColorClass
{
 public:
  virtual bool belongs(Pixel pix) = 0;
};
 
class ColorClassRGB : public ColorClass
{
  int minLum;
  double minCos;
 public:
  ColorClassRGB(int minLum, double minCos);
  virtual bool belongs(Pixel pix);
};
 
class ColorClassHSV : public ColorClass
{
  int minH, maxH;
 public:
  ColorClassHSV(int minH, int maxH);
  virtual bool belongs(Pixel pix);
};
 
class Vision
{
 public:
  void init();
  void use(Image &img, ColorClass *color);
};
 
Vision vision;
 
void Vision::init()
{
//  ColorClass *color = new ColorClassRGB(20, 0.99); // one
  ColorClass *color = new ColorClassHSV(20, 50); // or the other
  use(img, color);
}
 
void Vison::use(Image &img, ColorClass *color)
{
  for(int i = 0; i < img.w; i++) for(int j = 0; j < img.h; j++)
    if (color->belongs(img[i][j])) img[i][j]=Pixel(0,0,0);
}

It does the job, but it is not the best way, because all functions must be virtual, so they cannot be inlined and the code will be very slow if functions are called often.

Moreover this does not really respect the philosophy of inheritance. Inheritance represents the relationship “is a kind of”. But ColorClassRGB is not a kind of ColorClass, it is a ColorClass implementation.

Eventually, it does not always work. If you create the Animal class with a virtual clone function (that returns an Animal of course), and a Cow class which inherits from Animal, you would like that the clone function of Cow return a Cow, but you can't (overriden functions must have same signature). Thus your clone function must return an Animal, and if you want to use it as a Cow (because you know it is a Cow), you have to cast-down to a Cow, which is painful and absolutely not secure (possible errors at execution time).

Templates

There is another solution, which consists in using templates. Give the ColorClass as a template parameter. The use of this class will define what ColorClass must do (if something is missing, compilation will fail).
If you want to write the clone function, define a return_type that you will use without to know what it is, and which will be Cow or Dog etc.
Then there is no need for virtual functions, and you can inline what you want.

class ColorClassRGB
{
  int minLum;
  double minCos;
 public:
  ColorClassRGB(int minLum, double minCos);
  bool belongs(Pixel pix);
};
 
class ColorClassHSV
{
  int minH, maxH;
 public:
  ColorClassHSV(int minH, int maxH);
  bool belongs(Pixel pix);
};
 
template<class ColorClass>
class Vision
{
 public:
  void init();
  void use(Image &img, ColorClass *color);
};
 
//Vision<ColorClassRGB> vision; // one 
Vision<ColorClassHSV> vision; // or the other
 
void Vision::init()
{
//  ColorClass *color = new ColorClass(20, 0.99); // one
  ColorClass *color = new ColorClass(20, 50); // or the other
  use(img, color);
}
 
void Vison::use(Image &img, ColorClass *color)
{
  for(int i = 0; i < img.w; i++) for(int j = 0; j < img.h; j++)
    if (color->belongs(img[i][j])) img[i][j]=Pixel(0,0,0);
}

As you can see, the only problem of defining what a class must do by how we use it, is that they should have the same constructor signature, or you will have to modify also the construction to switch between implementations (still, being able to inline functions can be worth it).

The ugly and the pretty

Different ways to do some stuff.

Redo a loop part

Do a loop part again with the same value of the counter.

for(int i = 0; i < n; i++)
{
  if (tab[i] == -1)
  {
    swap(tab[i], tab[n-1]);
    n--;
    i--;
  } else
  do_some_stuff(tab[i]);
}

It works. But it won't work in some other cases, if your counter is not just an integer but a pointer scanning a list for example. It's ugly.

A nicer workaround :

bool redo = false;
for(int i = 0; i < n; i+=(redo?0:1), redo=false)
{
  if (tab[i] == -1)
  {
    swap(tab[i], tab[n-1]);
    n--;
    redo = true;
  } else
  do_some_stuff(tab[i]);
}

Super break

Break several nested loops.

for(int i = 0; i < n1; i++)
for(int j = 0; j < n2; i++)
{
  if (tab[i][j] == -1) goto break;
}
break_:

A nicer workaround :

bool break_ = false;
for(int i = 0; i < n1 && !break_; i++)
for(int j = 0; j < n2 && !break_; j++)
{
  if (tab[i][j] == -1) { break_ = true; break; }
}

A finally block

Do a block of code before returning a function, when there are a lot of return statements in this function.

In this case, as there is no try {} finally {} block in c/c++, I use the solution with goto, because workarounds would be really painful (copy the finally block everywhere, or set a flag to jump next steps).

  for(int i = 0; i < n; i++) if (tab1[i] = a) goto finally_;
  for(int i = 0; i < n; i++) if (tab2[i] = a) goto finally_;
  for(int i = 0; i < n; i++) if (tab3[i] = a) goto finally_;
 
 finally_:
  free(var);
  return false;

Swap code blocks

Change the order of execution of two blocks of code according to a variable (without duplication of code of course !).

There is not really ugly and pretty ways. Ok, a pretty way would be for sure to create two functions :

int x_first = 0;
if (x_first == 1)
{
  do_for_x();
  do_for_y();
} else
{
  do_for_y();
  do_for_x();
}

But when the blocks are short, I don't like creating functions called only once because it obliges to scroll when reading.

You could do it with goto too :

int x_first = 0;
int first_done = 0;
if (x_first == 1) goto do_for_x; else goto do_for_y;
do_for_x:
  code_for_x...
  if (first_done == 0) { first_done = true; goto do_for_y; } else goto do_end;
do_for_y:
  code_for_y...
  if (first_done == 0) { first_done = true; goto do_for_x; } else goto do_end;
do_end:

But it's really ugly.

The solution I prefer is to use a loop :

int x_first = 0;
for(int k = 0; k <= 1; k++)
{
  if (k == x_first)
  {
    code_for_y...
  } else
  {
    code_for_x...
  }
}

Copy of abstract objects

Clone function

You have an abstract class, and several implementations of this class. You have a pointer to the abstract class, but you don't know which implementations it is, and you want to make a copy of this object. The solution is to use a clone function.

class Descriptor
{
 public:
  virtual Descriptor* clone() = 0;
};
 
class Type1Descriptor: public Descriptor
{
 public:
  virtual Descriptor* clone()
  {
    return new Type1Descriptor(*this);
  }
};
 
class AnotherClass
{
  Descriptor *my_descriptor;
 public:
  AnotherClass(Descriptor *modelDescriptor)
  {
    my_descriptor = modelDescriptor->clone();
  }
};

Factory model

If you just want to copy the configuration parameters of the class, you can create a Factory class that will have the same constructor parameters than your class and will store them internally, and that has a create function that will create a copy of the class with these parameters.

class Descriptor
{
 public:
  virtual void describe() = 0;
  Descriptor(int param1, int param2): param1(param1), param2(param2) { internalData = 0; }
};
 
class DescriptorFactory
{
 public:
  virtual Descriptor* create() const = 0;
}
 
class Type1Descriptor: public Descriptor
{
  int param1;
  int param2;
  int internalData;
 public:
  Descriptor(int param1, int param2): param1(param1), param2(param2) { internalData = 0; }
  virtual void describe() { ... }
};
 
class Type1DescriptorFactory: public DescriptorFactory
{
  int param1;
  int param2;
 public:
  Descriptor(int param1, int param2): param1(param1), param2(param2) {}
  virtual Descriptor* create() const
  {
    return new Type1Descriptor(param1, param2);
  }
}
 
 
class AnotherClass
{
  Descriptor *my_descriptor;
 public:
  AnotherClass(DescriptorFactory *descriptorFactory)
  {
    my_descriptor = descriptorFactory->create();
  }
};

Inherited parameters

First see Modular architecture to see why you should maybe use templates instead of inheritance here.

You want two descriptors of same type being able to merge. So you have to declare it in the base class, with the base type, in order to be able to use it in general. But you don't know how to merge two different kinds of descriptors. If you implement a “generic merger” (with base class as parameter) that does nothing, it will be used in priority, even if you overloaded it with inherited class. The only solution is dynamic casting.

class Descriptor
{
 public:
  virtual void merge(Descriptor* desc) = 0;
};
 
class Type1Descriptor
{
 public:
  virtual void merge(Descriptor* desc)
  {
    Type1Descriptor *desc1 = dynamic_cast<Type1Descriptor>(desc);
    if (desc1 == NULL)
    {
      std::cout << "Error: cannot merge Type1Descriptor with another type of Descriptor" << std::endl;
      return;
    }
    // do the merging of two Type1Descriptor here
  }
};

C style tips

Generic code

As there is nothing such as templates in C, it is more difficult to make generic code. But not impossible. There are at least two ways.

Use void*

Write all your generic code to work with void* types, and using parameter functions that works with void* too.

Example:

typedef struct Queue_
{
	void **elements;
	int size;
	int first, last;
} Queue;
 
void pushQueue(Queue *q, void *elt)
{
	if (((q->last+1)%(q->size+1)) == q->first) return; // full
	q->elements[q->last] = elt;
	q->last = (q->last+1)%(q->size+1);
}

Problems:

  • functions given in parameter cannot be inlined. For the comparison function in a sort for example, it can be critical.
  • you cannot use members of structures passed by void* (because you don't know it yet…)

Use multiple included file

Define all the necessary types and operations with macros, as well as a macro to give a different name to functions every time the file is included, use them in your generic code, and define them before including the file.

Example:

/* sort.h */
void FNAME(insertionSort)(SORT_TYPE *array, int size)
{
	for(int i = 1; i < size; ++i)
	{
		SORT_TYPE val = array[i];
		int j = i;
		while(j > 0 && COMPARE(GET_KEY(val), GET_KEY(array[j-1])))
		{
			array[j] = array[j-1];
			--j;
		}
		array[j] = val;
	}
}
 
 
/* somefile.c */
#undef FNAME
#undef SORT_TYPE
#undef KEY_TYPE
#undef GET_KEY
#undef COMPARE
#define FNAME(name) name##_exval
#define SORT_TYPE ExampleTmp*
#define KEY_TYPE real
#define GET_KEY(x) x->val
#define COMPARE(a,b) (a < b)
#include "sort.h"
 
#undef FNAME
#undef SORT_TYPE
#undef KEY_TYPE
#undef GET_KEY
#undef COMPARE
#define FNAME(name) name##_exscore
#define SORT_TYPE Example*
#define KEY_TYPE real
#define GET_KEY(x) x->score
#define COMPARE(a,b) (a < b)
#include "sort.h"
 
insertionSort_exval(...);
insertionSort_exscore(...);
programming/cpp-style-tips.txt · Last modified: 2013/09/19 16:41 (external edit)
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0