Pure Interfaces

In my opinion, one disadvantage of c++ is that there exists no explicit interface concept or language feature. Of course, you can implement interfaces in c++ but you must use an abstract. The downside of this concept is the fact that an abstract class can already contain implementations and definitions or implementations of private or protected members or functions. Therefore, it allows to have elements which should not be part of an interface.

But before we start to analyze this in detail we want step back and define some terms. In most type-safe object-oriented programming languages with will find the concept of interfaces, abstract classes and concrete classes. An interface is a syntactical contract only. It defines the methods a class must contain. An abstract class also contains contract definitions and additional it already contains implementations. As an abstract class contains contract definitions for methods which must be implemented, it cannot be instantiated. Instead it is thought as base class for concrete classes. If a concreate class is based on an abstract class, it can use the implementations of the abstract class and it must implement the methods defined as contract but not implemented in the abstract class. A concrete class contains implementations only and therefore it can be instantiated. It can be derived from an interface and/or an abstract class and of course it can be implemented without using a parent element.

In c++ we don’t have an implicit language feature to implement interfaces. But we have abstract and concrete classes. An abstract class can be implemented by adding a contract for a method which must be implemented by a concreate class. In c++ we can implement such a contract by using a pure virtual method. If we want to implement an interface, we can do this by implementing an abstract class with pure virtual functions only. Therefore, you can implement interfaces in c++ but you must use an abstract class. As described at the beginning, abstract classes and interfaces are two independent elements in object oriented concepts. As c++ does not distinguish these two concepts, the compiler cannot prevent according implementation errors. For example, if you want to implement an interface, you can add elements (e.g. implemented methods) which will make the interface to an abstract class. But c++ cannot prevent this smelly software design. So, as a developer, you are responsible to write interfaces which are according object-oriented concepts. At next we will look at an example and think about a possible code design.

Let’s start with an example. We want to implement an application which is used to show and edit documents of different types. Therefore, we need some kind of document class which offers methods to manage a document. Within the example we want to use a base class “document” and two derived classes “TextFile” and “HtmlFile”. We will start with the load and save features of the document. In this article, we will think about the document data management only and offer an according interface which can be used by the client application. The following source code shows a possible implementation.

class Document
{
public:   // interface for clients of Document
  virtual void Load(std::string fileName);
  virtual void Save();

protected:  // common functions for implementers of Document
  std::string Serialize();
  void DeSerialize(std::string data);
  std::string CalculateHash();

protected:  // common data for implementers of Document
  std::string mFileName;
};

class TextFile : public Document
{
public:
  void Load(std::string fileName);
  void Save();

protected:
  std::string mEncoding;
};

class HtmlFile : public Document
{
public:
  void Load(std::string fileName);
  void Save();
};

 

The base class “document” contains public implementations for the load and the save methods. These public methods are our interface for the client application. Furthermore, it contains protected methods to serialize and de-serialize data, a function to calculate a hash code which is needed for some security features and it contains internal data about the loaded document. These protected methods and protected data members are an implementation help for the derived classes which can use these methods and data members. The derived classes can use the already implemented load and save methods or if needed they can overwrite them. Furthermore, they can add new elements like the “mEncoding” member in the “TextFile” class.

This implementation seems to solve our needs. And of course, you will find implementations of this kind very often in existing code. But based on the thoughts we had have at the start of the article we must ask: is this a good software design? What do you think?

 

Single Responsibility

In my opinion, there is one major issue regarding the above implementation: the class “Document” has four responsibilities. It provides the interface for client, it contains document specific functions used by derived classes, it contains generic functions which could be needed by other classes and not only derived ones and it manages the document data.

According the “single responsibility principle” such a design has many disadvantages. Due to the unnecessary dependencies, the code will be bad to maintain, changes will result in higher effort and compiling takes longer. So, we should try to split the document class into four separate classes, each responsible for one topic.

The following source code shows a possible implementation.

class DocumentInterface
{
public:   // interface for clients of Document
  virtual void Load(std::string fileName) = 0;
  virtual void Save() = 0;
};

class DocumentTools
{
protected:  // common functions for implementers of Document
  std::string CalculateHash();
};

class DocumentData
{
protected:  // common data for implementers of Document
  std::string mFileName;
};

class Serializer
{
public:  // common functions 
  std::string Serialize();
  void DeSerialize(std::string data);
};

 

We have three document specific classes, one for the interface, one for common helper functions used to implement derived classes and one for the data management. Furthermore, we have created a generic serializer class as it offers common serialization features which may be used in other uses cases too. So, this implementation can be reused in other scenarios and is no longer limited to documents.

 

Composition vs. Inheritance

The nice separation of concerns principle forces us to implement four independent classes. To implement our document specific features, we will use and connect these classes. This connection can be created by using two main concepts: composition and inheritance.

We know our classes “TextFile” and “HtmlFile” are both documents which must implement the document interface. Therefore, we found a first need for inheritance. But most often it isn’t that easy and so it isn’t in this case too. We could think about two main designs: implement the interface directly or implement a base class. “TextFile” as well as “HtmlFile” are both documents. Maybe we have some advantages if we use a base class “document” which implements the interface and we derive from this class. The following source code shows both possibilities.

// inheritance without base class
class DocumentInterface {};
class TextFile : public DocumentInterface {};
class HtmlFile : public DocumentInterface {};

// inheritance with base class
class DocumentInterface {};
class DocumentBase : public DocumentInterface {};
class TextFile : public DocumentBase {};
class HtmlFile : public DocumentBase {};

 

Beside the decision about the kind of inheritance we want to use, we should decide whether we want to use inheritance at all. This will lead us to the well-known “composition vs. inheritance” topic. Let’s assume we implement a document base class. This base class can derive from the tool and data classes or it can use the tool and data classes. The following code shows these possibilities.

// inheritance for additional classes
class DocumentInterface {};
class DocumentTools {};
class DocumentData {};
class Serializer {};
class DocumentBase : public DocumentInterface, public DocumentTools,
  public DocumentData, public Serializer {};

// composition for additional classes
class DocumentInterface {};
class DocumentTools {};
class DocumentData {};
class Serializer {};
class DocumentBase : public DocumentInterface
{
private:
  DocumentTools mTools;
  DocumentData mData;
  Serializer mSerializer;
};

 

As we can see we must make some fundamental design decisions before we start to implement the document feature. At first, we should decide whether we want to implement a base document class. Such a base class makes sense if we have some common functionality which is needed in several sub classes. For example, if we can implement the “Load” and “Save” functions in a generic way, we should implement them only once. In this case these functions should be implemented in a base class and can be used by all derived classes.

At next we should think about the composition vs. inheritance topic. If you have two classes and you want to choose the type of dependency, you could ask: “Is x also a y? Or does x only use y?”. For example, think about the dependency between “TextFile” and “Document”. Is the “TextFile” a “Document”? I think: Yes, it is. Therefore, we have a inheritance connection between them. What is with “HtmlFile” and “Serializer”? Is the “HtmlFile” a “Serializer”? I don’t think so. But the “HtmlFile” may use the “Serializer”. Therefore, we should use a composition in this case.

 

Possible class design

Based on the Thoughts so far, I want to implement a suitable class design. As a general rule, I would recommend avoiding dependencies. Each functionality should be an own feature and implemented independent from the other parts of the software. This will increase reusability, maintainability, the software will be easier to understand, unit-testing will be much easier and so the software gets a higher quality.

Of course, dependencies are needed sometimes. If a complex feature should be done, it needs the combine the different functionalities of the independent classes and combine them to solve a more complex task. That’s the point where we want to create dependencies. Depending on the use case, we will select the corresponding single classes needed to solve the use case and combine them to a more complex system.

The following source code shows an implementation according this rule. There are several independent classes. As we want to use the features of this classes to manage documents, we will combine the single tasks (classes) by using them in one complex task (class). So, we create a document base class which creates the dependency between the document specific data class, the document specific tool class, the independent tools and the client interface. This base class will then be starting point for concrete document classes. These will be derived from the base class and may use their functionality or implement their own features.

// interface for clients of Document
class DocumentInterface
{
public:   
  virtual void Load(std::string fileName) = 0;
  virtual void Save() = 0;
};

// common functions for implementers of Document
class DocumentTools
{
protected:  
  std::string CalculateHash();
};

// common data for implementers of Document
class DocumentData
{
protected:  
  std::string mFileName;
};

// service class which is independent from document features 
// an may be used used in other application units too
class Serializer
{
public:  
  std::string Serialize();
  void DeSerialize(std::string data);
};

// base class for all documents with
// base implementation of the document interface
class DocumentBase
{
public:   
  virtual void Load(std::string fileName);
  virtual void Save();

protected:
  DocumentTools mTools;
  DocumentData mData;

private:
  Serializer mSerializer;
};

// document class, derived from document base
// may use the implementations of the base class
// may add additional functions
class TextFile : public DocumentBase
{
protected:
  std::string mEncoding;
};

// document class, derived from document base
// may use the implementations of the base class
// may add additional functions
class HtmlFile : public DocumentBase
{
};

 

Pure interfaces

Based on the fundamental consideration about interfaces in object oriented languages, we have analyzed a messy implementation example and have thought about the interface concept in c++. This first concept, of separation between interfaces, abstract classes and concreate classes was the base idea of the further design decisions und design guidelines to implement classes without dependencies to each other and create a connection between them only at higher level in use case specific scenarios.

In summary, the basis of the design was a clear separation between interfaces, base classes and concrete classes. As we don’t have an explicit language concept for interfaces in c++, we should create an implicit rule: “Make pure Interfaces”. As you want to implement an interface for a client, you should use an abstract class, but it must contain public pure virtual functions only.

Advertisements
Veröffentlicht unter C++ | Kommentar hinterlassen

Casting in C++, Part 2

Within the first part of the article we have seen the existing type of casts and we have analyzed the c++ style operators for static cast and dynamic cast. We will now continue with the const cast and reinterpret cast operator and finish the topic with some more advanced topics like comparison between dynamic and static cast and the disadvantages of c style casts.

const_cast

The const cast operator typically used to cast away the constness of an object. It is the only c++ style cast that can do this. Const cast is considered safer than simple type casting because it won’t happen if the type of cast is not same as the type of the original object.

Like any other cast operator, the const cast should be used wisely. A constant object is normally explicitly constant to avoid misusing and possible application errors or undefined behavior. The following example shows a possible use case. Let´s say we have an object which allows to execute data queries. Such a query should analyze the data only and therefore the according method is defined as const, so the this-pointer is const and the data of the object cannot be changed within the method.

class DataQuery
{
public:
  DataQuery()
  {
  };

  int ExecuteQuery(const std::string query) const
  {
    return 42;
  }
};

Now you want to extend the actual implementation with a query counter. This may be easy as you can add a new object member and increase it by every call to the query method. But unfortunately, you are not allowed to change the object interface (for example to avoid conflicts with clients). As the method is defined as const and therefore the this-pointer is const, you cannot increase your member variable. In such a case, you can use the const cast operator to cast away the constness of the this-pointer. The following source code shows the adapted example.

class DataQuery
{
public:
  DataQuery() : mCounter{ 0 }
  {
  };

  int ExecuteQuery(const std::string query) const
  {
    (const_cast<DataQuery*>(this))->mCounter++;

    return 42;
  }

private:
  int mCounter;
};

Of course, in such a case you may ask whether this is a clean solution of the issue or just a workaround to bypass an environment limitation, in this case the fixed interface. In my opinion, a const cast is always a workaround. A clean architecture and implementation should not have a need to use a const cast operator.

But why may it sometimes by dangerous to cast away the constness and sometimes it is ok? And how can you recognize and distinguish these two situations? The following two examples show an interesting aspect which may help you to answer these questions. Let´s say we have a variable and a constant pointer to this variable. That’s typical in many situations, for example in the above example with the query counter we had have an internal data member and a constant pointer to the data (the this-pointer). Furthermore, we have a function which changes data and therefore you have a non-const pointer to the data. The following source code shows a possible implementation of such a use case.

void fun(int* pValue)
{
  *pValue = *pValue + 10;
}

int _tmain(int argc, _TCHAR* argv[])
{
  int value = 10;

  const int *pValue = &value;
  int* pValueNotConst = const_cast<int*>(pValue);
  fun(pValueNotConst);

  std::cout << value;
  return 0;
}

What do you think: Is it allowed to cast away the constness in this case? Please think about this question for a short moment…

And now we will do a little modification and define the origin integer value as const too.

void fun(int* pValue)
{
  *pValue = *pValue + 10;
}

int _tmain(int argc, _TCHAR* argv[])
{
  const int value = 10;

  const int *pValue = &value;
  int* pValueNotConst = const_cast<int*>(pValue);
  fun(pValueNotConst);
  
  std::cout << value;
  return 0;
}

What do you think now: Will this change your opinion whether the cast is allowed or not? Is it allowed in both cases, just in one or maybe in none of the two examples?

Within the first of the two examples the origin variable is not const. You can modify the value and therefore it is fine to cast away the constness of the pointer to change the data of the variable. In the second example, the origin data is const and therefore you should never change it. If you bypass this limitation and try to change the value, you may result in undefined behavior – in the above example the value of the variable is still “10” even after function call.

Of course, the implementation of the first example is dangerous too. Even if it works now it may be an issue in future, for example if someone changes the constness of the origin variable. In such cases the variable and the client code with the cast are normally not within three lines of code inside a method. Instead they are often far away from each other, in different classes and modules. Such a change will result in annoying and costly troubleshooting.

reinterpret_cast

By using the reinterpret cast operator the given data is interpreted as it has the new type. This cast will not do a type convert. It will read the memory you passed in a different way. You give it a memory location and you ask it to read that sequence of bits as if it had the new type. Therefore, it can only be used with pointers and references. Reinterpret cast is intended for low-level casts that yield implementation dependent results, for example casting a pointer to an int. Such casts should be rare outside low-level code.

The following code shows an example were the given unsigned short integer value is reinterpreted as signed short integer.

int _tmain(int argc, _TCHAR* argv[])
{
  unsigned short int value1 = 30;
  unsigned short int value2 = 40000;
  
  short int value3 = *reinterpret_cast<short int*>(&value1);
  short int value4 = *reinterpret_cast<short int*>(&value2);

  std::cout << value3 << std::endl;   // value is like expected
  std::cout << value4 << std::endl;   // may result in undefined behaviour

  return 0;
}

Such a reinterpretation may work or it may result in undefined behavior. Within this example you have such a situation in case the value range of the source data type exceeds the value range of the target data type. Therefore, if you use reinterpret cast, you must know what you are doing as the compiler cannot detect such logical issues. Reinterpret cast is very dangerous and why it should not be used in this type of cases. You should only use it when you have a pointer and you need to read that memory location in a certain way and you know that the memory can be read in that way.

dynamic vs. static cast

In some situations, you may not be sure whether to use a dynamic cast or a static cast. The advantage of using a dynamic cast is that it allows to check whether a conversion has succeeded during run-time. The disadvantage is that there is a performance overhead associated with this check.

If you want to cast a derived class to its base class, a dynamic cast as well as a static cast will give you the right result. As the dynamic cast coms with a performance overhead you should use a static cast in this case.

If you want to cast a base class to its derived class the conversion may be succeed or fail depending whether your class is of the expected type or not. A dynamic cast will check whether the conversion is possible or not. Therefore, you should prefer a dynamic cast in this situation as a static cast may result in undefined behavior.

The following example contains both situations, a derived-to-base cast and a base-to-derived cast.

class Animal
{
public:
  virtual void Print() const
  {
    std::cout << "animal" << std::endl;
  };
};

class Bird : public Animal
{
public:
  void Print() const
  {
    std::cout << "bird" << std::endl;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  
  Animal animal1 = static_cast<Animal>(bird);  // OK
  Animal* animal2 = dynamic_cast<Animal*>(&bird);  // OK, but slower

  Bird* bird1 = static_cast<Bird*>(animal2);   // may result in undefined behavior
  Bird* bird2 = dynamic_cast<Bird*>(animal2);  // checks whether conversion is possible
    
  return 0;
}

Disadvantages of c style casts

As mentioned before you should avoid c style casts. They are not bad at all or will inevitably lead to errors, but compared to the new c++ style cast they have some disadvantages and therefore a higher possibility of misuse. Following I want to show some examples to explain the disadvantages of c style casts.

We will start with a typical situation: existing code will be changed. Of course, this will happen often in daily business and unfortunately such changes, even little ones, may introduce new errors. The following example shows a typical situation where a function “foo” is called which calls another function “bar”. As bar expects a derived class we must convert the parameter. Later, the function foo must be changed a little bit and the parameter should be passed as const parameter. The function “foo2” will show this change. Unfortunately, by using the c style cast, we will cast the constness of the parameter away. Depending on the implementation details of “foo2” and “bar” this may lead to unexpected behavior.

class Animal{};
class Bird : public Animal{};

void Bar(Bird* bird)
{
}

// origin function with c style cast
void Foo(Animal* animal)
{  
  Bird* bird = (Bird*)animal;
  Bar(bird);
}

// new function with c style cast
void Foo2(const Animal* animal)
{
  Bird* bird = (Bird*)animal;
  Bar(bird);
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();  
  Foo(&bird);
  
  return 0;
}

If we have the same situation but implement it by using a c++ style cast, the compiler will detect such an issue and you get a compiler error. The following code shows the same example with a c++ style cast.

class Animal
{ 
public:
  virtual ~Animal(){}; 
};
class Bird : public Animal{};

void Bar(Bird* bird)
{
}

// origin function with c++ style cast
void Foo(Animal* animal)
{  
  Bird* bird = dynamic_cast<Bird*>(animal);
  Bar(bird);
}

// new function with c++ style cast
void Foo2(const Animal* animal)
{
  Bird* bird = dynamic_cast<Bird*>(animal);  // compiler error
  Bar(bird);
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();  
  Foo(&bird);
  
  return 0;
}

In c we have no classes. But we can use c style cast to convert base-to-derived class types and vice versa. How is this possible? If you think about this question you found another issue regarding c style cast. As seen within the section “dynamic vs. static cast” a derived-to-base cast is harmless. That’s also true if you use c style casts. But a base-to-derived class may result in undefined behavior. If you use a c style cast in this case, it behaves like a reinterpret cast. And unfortunately, this will often result in undefined behavior, as many developers will expect that the cast is done well and they not expect a reinterpret cast in this situation. The following example shows such a situation.

class Animal
{
public:
  virtual void Print() const
  {
    std::cout << "animal" << std::endl;
  };
};

class Bird : public Animal
{
public:
  void Print() const
  {
    std::cout << "bird" << std::endl;
  }
};

class Fish : public Animal
{
public:
  void Print() const
  {
    std::cout << "fish" << std::endl;
  }
};

void Foo(const Animal* animal)
{
  animal->Print();

  const Bird* bird = (Bird*)(animal);
  if (bird)
  {
    bird->Print();
  }

  const Fish* fish = (Fish*)(animal);
  if (fish)
  {
    fish->Print();
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  Fish fish = Fish();

  Foo(&bird);
  Foo(&fish);

  return 0;
}

If you implement the above example by using c++ style casts you will explicitly select one of the four cast operators. In this case the dynamic cast will be your choice. This explicit operator selection is a big advantage of c++ style casts over c style casts. It will make the code more robust, as the compiler is now able to detect programming errors, and it will make the code more readable as it now contains an explicit information what we want to do.

If you use c style casts, you sign a contract with your compiler and promise: “I know what I am doing”. This may be fine four you and I’m sure you really know what you are doing. But unfortunately, in the same moment you add something more to this contract: “I also know what other programmers are doing and I know they know what I am doing.” This sound like a strange promise which cannot be fulfilled. But as you are most often not the only developer ever touching this code, you will implicitly give this promise by using c style casts.

Summary

Using the four c++ style casting operator’s makes the code more readable and more maintainable. It makes the logic behind the code more explicit. And it makes the code less error-prone by having the compiler catch errors either as you’re making them or later as you go back and change old code.

But on the other hand, you should not often have to use cast operators as they indicate software design issues.

In summary, I want to define three simple guidelines:

First guideline: Do not use casts. Instead check whether the software design is suitable.

Second guideline: If you must cast, use the c++ style cast operators.

Third guideline: Avoid dynamic cast in performance sensitive code.

Veröffentlicht unter C++ | Kommentar hinterlassen

Casting in C++, Part 1

The rules of C++ are designed to guarantee that type errors are impossible. Unfortunately, casts subvert the type system. That can lead to all kinds of trouble. Casting is a fundamental concept but it should be used with caution. A good software design helps to reduce the number of needed casts but sometimes they are needed. Within this article I want to analyze the different types of casting, how they are used and what kinds of issues may occur on unconsidered use of casts.

 

Types of casts

In c++ applications, you can find some different kinds of casts. There are implicit casts, c style casts, c++ functional cast expressions and c++ style casts. The following source code shows a conversion from a float into an int value by using the different kinds of casts.

int _tmain(int argc, _TCHAR* argv[])
{
  float a = 17.4f;
  int b;
  
  b = a;                      // implicit conversion
  b = (int)a;                 // c style cast
  b = int(a);                 // c++ functional cast expression
  b = static_cast<int>(a);    // c++ style cast

  return 0;
}

 

At the end of the article we will see this example again and identify the cast type to prefer. Now, let’s start by thinking about the different types of casts and understand their behavior.

The implicit cast “b = a” may or may not have side effects depending on the types of a and b. For example, an implicit cast from float to int results in a loss of data precision. As this may not be intended by the developer most compilers will generate compiler warnings in this case.

C style casts “(T)expression” are available to ensure downward compatibility with c. Unlike in c++, there was only one operator in c to convert data types. Since c does not know any classes and therefore no methods, the type conversion is correspondingly limited to the base data types. In c++, the c cast was extended to the c++ structures. Thus, you can do almost anything with a c cast as with one of the four c++ cast operators.

The functional cast expression used in this example “T(expression)” consists of a simple type specifier followed by a single expression in parentheses. This cast expression is exactly equivalent to the corresponding c style cast. Furthermore, the functional cast expression is available in some other variants, for example more than one expression can be used inside the parentheses. This cast looks like a constructor. And often it is as it results in a constructor call. Conversion is a form of initialization. When a type is implicitly convertible to another, a functional cast is a form of direct initialization. The compiler knows which types are convertible.

The c++ style cast – also called new style cast – offers four new cast forms: const_cast(expression), dynamic_cast(expression), reinterpret_cast(expression) and static_cast(expression). The c++ style cast will lead to compiler errors when used incorrectly. In addition, readers of the source code are roughly informed about the intention of the cast as one out of the four cast forms is explicitly used.

In c++ you should use the new style casts. We will see explanations for this guideline within the further course of the article. Therefore, the following paragraphs are focused on the c++ style casts. At first, we want to understand the for new cast forms. Afterwards, we will come back to the c style cast and see some of the issues which may occur and how these are avoided by using the new style casts.

 

static_cast

The static cast operator is the most popular and most commonly used one. It converts data type by using an existing conversion rule. Such a rule may be for example a constructor or an overloaded cast operator. The static cast is done at compile time.

The elementary data types can be largely converted into one another. However, this also clearly shows the greatest disadvantage of a type transformation: it almost always goes with data loss. For example, if you convert a floating-point number to an integer, all decimal places are lost.

The following example shows a typical use case for the static cast operator: a division of two integers where the result shall be a floating-point number.

int _tmain(int argc, _TCHAR* argv[])
{
  int x = 10;
  int y = 11;
  
  double z = x / y;
  std::cout << z << std::endl;

  z = static_cast<double>(x) / y;
  std::cout << z << std::endl;

  return 0;
}

 

The first output is “0” because the implicit cast will remove the decimal places. The second output is “0.9” because with the static cast the variable was casted to a floating-point number.

 

The static cast can be used to force implicit conversions like from int to double or from non-const to const objects. So, you can use it to add constness to an object. Furthermore, the static cast can be used to perform conversions like void* pointers to typed pointers and pointer-to-base to pointer-to-derived. The following example shows such a type conversion from a derived child class to the base class.

class Animal 
{
public:
  virtual void Print() const
  {
    std::cout << "animal" << std::endl;
  };
};

class Bird : public Animal 
{
public:
  void Print() const
  {
    std::cout << "bird" << std::endl;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  Animal animal = static_cast<Animal>(bird);
  
  bird.Print();
  animal.Print();

  return 0;
}

 

Within the above example we converted an object of child class to an object of a base class. What do you think will happen if we use pointers instead and additional add to opposite use case and convert from base to child? The following example will show some interesting results.

class Animal
{
public:
  virtual void Print() const
  {
    std::cout << "animal" << std::endl;
  };
};

class Bird : public Animal
{
public:
  void Print() const
  {
    std::cout << "bird" << std::endl;
  }

  void Print2() const
  {
    std::cout << "bird2" << std::endl;
  }
};

class Car
{
public:
  void Print() const
  {
    std::cout << "car" << std::endl;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{  
  Bird* pBird = new Bird();
  Animal* pAnimal = static_cast<Animal*>(pBird);  // this works
  
  pBird->Print();
  pAnimal->Print();
  //pAnimal->Print2();  // ERROR - Won't compile   

  pBird = static_cast<Bird*>(pAnimal); // this works
  pBird->Print();
  
  pAnimal = new Animal();
  pBird = static_cast<Bird*>(pAnimal); // this works
  pBird->Print();
  pBird->Print2();
  
  //Car* pCar = static_cast<Car*>(pBird); // ERROR - Won't compile   
  
  return 0;
}

 

The application creates the following output:

bird
bird
bird
animal
bird2

 

We can see that the first conversion converts the pointer to a base class pointer. Of course, we cannot call the child class method “Print2” but if we call “Print” we can see that the child class function is still used. At next we convert this pointer back to the child class pointer which is fine as the underlying object is of type “Bird”. Within the last use case we create a base class and convert the pointer of the base class to a pointer of the child class. This will work but interestingly the function calls will result in a call of the base class function “Print” and the child class function “Print2”. This example will show a very important fact: you can use static cast operator to cast object pointers and to cast a base class pointer to a child class pointer, but this may result in unexpected or even undefined behavior. Later, if we look at the dynamic cast, we will see another example which compares dynamic and static casts in case of converting from base to child class. You may now think the compiler should show a warning or error in this case, but the compiler will allow downcasts to derived class. It cannot give compile time error because a base-derived relationship can exist at runtime depending on the address of the pointers being casted. Therefore, such static casts always succeed at compile time, but may raise undefined behavior at runtime if you don’t cast to the right type. If we want to detect and avoid casting errors at runtime, we must use a dynamic cast.

 

dynamic_cast

The dynamic cast operator is the only cast operator which is performed at runtime. This will allow a to write code which depends on the runtime state of a variable. Pointers and references can contain objects of their own type and objects of a derived class type. Therefore, it is possible, that the type of a variable is not known at compile time because at runtime the variable may be of the given type or of one of the existing derived types. The dynamic cast operator allows a safe downcast of a variable in one of the derived types.

The dynamic cast is the only cast operator which cannot be performed using the old c style syntax. It is also the only cast that may have a significant runtime cost. Therefore, you should not use it in situations where a static cast is sufficient.

If you want to downcast types of an inheritance architecture by using the dynamic cast, you must implement polymorph classes, which means they must have at least one virtual method. For example, you can write a virtual destructor.

The following source code shows an object hierarchy with polymorph classes.

class Animal
{
public:
  virtual void Print() const
  {
    std::cout << "animal" << std::endl;
  };
};

class Bird : public Animal
{
public:
  void Print() const
  {
    std::cout << "bird" << std::endl;
  }
};

class Fish : public Animal
{
public:
  void Print() const
  {
    std::cout << "fish" << std::endl;
  }
};

 

We can use these classes to write an example application. Within this example we will write a function with an input parameter of type “Animal”. Of course, we can pass variables of the derived classes “Bird” and “Fish” to this function too. Within the method we can convert the animal-object back to the derived class by executing a downcast using the dynamic cast operator. If the cast is successful, the result is a pointer to the object but now it is of the type given within the cast. If the object has another type than given in the cast operator, the result is a null pointer. Therefore, after executing a dynamic cast, you must check whether the resulting pointer is valid or a null reference. The following source code shows an according example.

void Foo(const Animal* animal)
{
  animal->Print();

  const Bird* bird = dynamic_cast<const Bird*>(animal);
  if (bird)
  {
    bird->Print();
  }

  const Fish* fish = dynamic_cast<const Fish*>(animal);
  if (fish)
  {
    fish->Print();
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  Fish fish = Fish();

  Foo(&bird);
  Foo(&fish);

  return 0;
}

 

Of course, it is also possible to use references instead of pointers. In this case the dynamic cast will throw an exception if the cast is not possible. The source code shows the adapted example.

void Foo(const Animal& animal)
{
  animal.Print();

  const Bird bird = dynamic_cast<const Bird&>(animal);  //throws an exception if called with 'fish'
  const Fish fish = dynamic_cast<const Fish&>(animal);  //throws an exception if called with 'bird'
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  Fish fish = Fish();

  Foo(bird);
  Foo(fish);

  return 0;
}

 

As mentioned above, dynamic cast are only available for polymorphic classes and dynamic cast can have significant runtime costs. This is because the RTTI (run-time type information) features are needed to safely convert the types. In practice, you will often have polymorphic classes anyway because base classes must have a virtual destructor to allow objects of derived classes to perform proper cleanup if they are deleted from a base pointer. So, this is not a limitation. But due to the runtime costs you should not execute dynamic casts if they are not needed.

The above source code shows a typical situation where dynamic cast is used. You will find such method in a lot of example applications, tutorials, books and of course in professional applications. But I think the method shown in the example is an example for bad software design too. The interface of the function tells the client that it expects an “Animal” object, but the implementation expects a “Bird” or “Fish”. This contradiction between interface design and functionality can lead to many issues and even unexpected behavior of your application. As this article is about casting and not about software design I don’t want to go further into this topic. But you should keep in mind, and that’s true for all four cast operators, that the need of a cast operator may be an indication for a bad software design. In source code with a clean design there is nearly no need for the cast operators.

Within the previous chapter, about the static cast, I mentioned that the static cast should not be used for a downcast. Therefore, to finish this topic we can test the behavior of the example application in case we use the static cast instead of the dynamic cast. The following source code shows a possible modification of the example application.

void Foo(const Animal* animal)
{
  const Bird* bird = static_cast<const Bird*>(animal);
  if (bird)
  {
    bird->Print();
  }

  const Fish* fish = static_cast<const Fish*>(animal);
  if (fish)
  {
    fish->Print();
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  Bird bird = Bird();
  Fish fish = Fish();

  Foo(&bird);
  Foo(&fish);

  return 0;
}

 

This looks like a valid implementation and it will compile without errors. It even cannot give compile time errors because a base-derived relationship can exist at runtime depending on the address of the pointers being casted. Static cast always succeeds, but will raise undefined behavior if you don’t cast to the right type. If you execute the example application you will get outputs you may not expect.

 

Preview on part 2

As we have seen two of the four cast operators now, I want to finish this first part of the topic. Within a next blog article, I want to continue this topic and explain the const cast operator and the reinterpret cast operator. Furthermore, I want to include a comparison of dynamic cast and static cast based on an example with base-to-derived and derived-to-base class conversion. Moreover part 2 will contain some more examples showing the disadvantages of the c style cast.

Veröffentlicht unter C++ | Kommentar hinterlassen

Object orientation in C# and C++

Within this article I want to think about the possible implementations in C# and C++ to fulfill the base concept of object orientation. That’s a difficult task because if you start to think about object orientation and ask yourself what is the “base concept” you may have several ideas.

I started to think about this topic relating to an analysis about the root causes of errors in past projects and issues in legacy code. The root cause of most errors is a violation of core software development concept. I think the most important concept is the programming paradigm you are using: object orientation, functional programming or procedural programming – to count the most important ones. The projects I have worked so far are mostly based on the object-oriented paradigm. Therefore, most issues were a result of violating object oriented concept. Moreover, I have seen one core concept which will be ignored very often, even by experienced software developers. Therefore, I want to work out the core concepts and think about possible implementation in C# and C++.

 

The core concept of object oriented programming

The object-oriented paradigm is based on few concepts like: objects, classes, encapsulation, interfaces, inheritance, messaging, composition, delegation, polymorphism and many more. But I think most of these concepts are optional features only. Of course, they are very important, but they are not necessary for object orientation. For example, think about “inheritance”. If you ask software developers about the concepts of object orientation you will hear “inheritance” as first, second or latest as third concept. But in my opinion, it is an optional feature only. You can implement object oriented without using inheritance and you can develop an object-oriented language which even does not support inheritance.

If all these things are optional features only, what will remain? In my opinion, the core concept of object orientation is: “Objects and their coupling, where an object is memory management hidden by an interface”.

Let us think about this approach. We have two core components: objects and (their) coupling. The easy part is “coupling” because if we have several objects then of course, they should work together somehow. The more difficult part is the “object”. That’s a well-known term in software development, but unfortunately there are a lot of different opinions about the question: What is an object?

I like to explain an object as: “memory management hidden by an interface”. That’s a very technical description but it contains the core concepts of on object and is independent of the used programming language.

At this point I want to stop and may ask you to find you own definition for object orientation. The above definition reflects my point of view only. You will find another one and of course their existing several definitions which are all fine.

 

Coupling of objects

As mentioned above “coupling” is the easy one of the two concepts. The concept itself is easy to understand and the implementation is well supported in most languages. And the violation of this concept does not result in errors in most cases. But it results in code which is difficult to understand, to maintain and to extend. So, a violation of this concept will increase the development costs.

So, what kind of coupling do we want to have between our objects? A very loose one! In a perfect world, objects will do their work independent of other objects. If an object shall do anything it gets a trigger and the needed information, executes its task and will inform the object(s) which are waiting to get the result. That will allow small, independent, reusable objects. Depending on the use case the needed object will be defined and loose coupled by establishing communication channels and then they will execute the task.

What will happen if we do not respect this concept an implement a system with a lot of dependencies between objects? It will lead to the same issues as we know from classical procedural programming using jump instructions like “goto”. The result is a software system with a complex control flow, better known as “spaghetti code”. As we banished “goto” statements in modern software systems, we also should try to banish object coupling.

There are several concepts to implement such system of loose coupled objects, for example: Event based programming. Within this article I don’t want to show possible implementation of such an event bases system. That’s because most programming languages offer very easy to use messaging or event mechanism. You will find a lot of online resources about possible patterns to implement event based systems. Therefore, I want to focus on the difficult part, the “object”.

 

Objects

As described before, I want to define an object as “memory management hidden by an interface”. The interface contains the public accessible methods and properties of the object. The implementation details itself are internal and hidden. So, the object is a black box and a client does know the public interface only. All internal details are hidden and the object has to have the responsibility to manage its resources. In most cases resource management is memory management. Of course, there are other resources like a network connection. So my definition for an object is not imperfect and should be changed to “resource management hidden by an interface”. But I prefer the term “memory management” as most of the implementation errors are associated with wrong memory management. The generic term “resource management” sometimes leads to misunderstanding of the real issue. For example, if your object contains an internal data member it is not sufficient to hide this resource itself by making it private. Moreover, you have to hide the memory management used by your private member.

Again, we can think about the consequences in case we don’t follow this concept. If we have object with public memory management it is the same as implementing with public variables only. Everyone can read and write these public variables at any time. This will result in a complex system of data flows. And compared with the issue of complex control flows, which we have seen in scenarios with a lot of dependencies between the objects, the situation gets even worse. Complex control flows are very difficult to understand and will normally result in much higher development costs. But complex data flows are a mess and will result in errors.

 

Private memory management

An object is a black box for the client. The memory management must be hidden and therefore not visible within the public interface, whether direct nether indirect. So, we have to respect this concept of hidden memory management for data which is used as input for the object and data which is used as output. Input data, e.g. ctor parameters, setter or function parameters, should allow accessing the data only and store it within the memory managed by the object. Output data, e.g. getter or function results, shall contain data only and shall not allow accessing the memory addresses where the data is stored. In summary, the public interface of an object defines the data flow to and from the object but it explicitly hides memory management details.

 

Base concept in C#

C# has an own memory management system and hides the internal pointer management. This concept of implicit referencing allows an easy and efficient memory handling. But as the developer will use pointers implicitly in form of reference types he may forget about the fact that variables of such types are pointers to memory which is managed by someone. Because of this implicit referencing you will find a lot of C# source code where the core concept of object orientation, the concept of hidden memory management, is violated.

The following source code shows an example implementation. We have an object, the “employee” class, with a public interface which is used by a client. And we have a second object, the “person” class, which encapsulates the management of a person. This person class is used by the employee object.

class Person
{
  public Person(string name, int age)
  {
    mName = name;
    mAge = age;
  }

  public string mName;
  public int mAge;
}

class Employee
{
  public Employee(Person person, string phoneNumber)
  {
    mPerson = person;
    mPhoneNumber = phoneNumber;
  }

  public Person Person
  {
    get { return mPerson; }
  }

  public void PrintName()
  {
    Console.WriteLine(mPerson.mName + ", " + mPerson.mAge.ToString() + ", " + mPhoneNumber);
  }

  private Person mPerson;
  private string mPhoneNumber;
}

class Program
{
  static void Main(string[] args)
  {
    Person person = new Person("John Doe", 32);
    string phoneNumber = "555 123456";
    Employee employee = new Employee(person, phoneNumber);

    employee.PrintName();
  }
}

 

As mentioned before we want to think about the memory management guideline only as this is the most difficult and critical aspect of the object-oriented concept. What do you think about this implementation? Is it according the object-oriented concept?

Unfortunately, it is not. And I say “Unfortunately” because I think you can see this kind of implementation very often within C# applications. But what’s the issue with this code? I can demonstrate this with a little modification of the client code.

class Program
{
  static void Main(string[] args)
  {
    Person person = new Person("John Doe", 32);
    string phoneNumber = "555 123456";
    Employee employee = new Employee(person, phoneNumber);

    employee.PrintName();

    person.mName = "Foo Bar";
    person.mAge = 41;
    phoneNumber = "555 111111";

    employee.PrintName();

    person = employee.Person;
    person.mName = "Jane Doe";
    person.mAge = 28;
    phoneNumber = "555 999999";

    employee.PrintName();
  }
}

 

Ups, the client can manipulate the object internal data. And he will not do this on purpose. The code shows typical use cases were the client works with variables he manages and he does not know or even expect that he changes something inside the employee object. Such code will result in critical errors.

Is this a fault of the C# language? No, it isn’t. C# will protect the pointer but not it’s content. The pointer itself is immutable unless you specify a “ref” modifier. So, you cannot change the pointer but of course you can access and change the data of the pointer.

The error occurred as the object shows the memory management within its public interface. The ctor parameter is a reference to memory and the getter property is a reference to memory too. So, the memory management is not hidden, instead it is totally transparent. This violates the core concept of object orientation and results in such critical errors.

Following I want to show two possible implementations for this use case. Of course, these two implementations are not the only ones, but they show two common concepts.

 

Pass copies and return copies in C#

The object and the client want and must work with their own independent data. Therefore, unless whether they use different data type or whether they even if they use the same data structures – in this example the person class – the data must be available as often as they are used. Within this example the client creates an employee object and passes a person object. So, it manages one person instance. The employee object itself contains a hidden internal data member which is also a person class. And later, the client or maybe another client will get data from the employee class. This data contains a person class too. But of course, these three instances of the person class are managed in an own context. So, they must be independent of each other which means they must contain the same data but an own memory management. And that’s easy to implement. We just should create copies. The following source code shows a possible implementation.

class Person
{
  public Person(string name, int age)
  {
    mName = name;
    mAge = age;
  }

  public Person(Person person)
  {
    mName = person.mName;
    mAge = person.mAge;
  }

  public string mName;
  public int mAge;
}

class Employee
{
  public Employee(Person person, string phoneNumber)
  {
    mPerson = new Person(person);
    mPhoneNumber = phoneNumber;
  }

  public Person Person
  {
    get { return new Person(mPerson); }
  }

  public void PrintName()
  {
    Console.WriteLine(mPerson.mName + ", " + mPerson.mAge.ToString() + ", " + mPhoneNumber);
  }

  private Person mPerson;
  private string mPhoneNumber;
}

 

This implementation has on major disadvantage: copying of object may be slow, especially if you have huge objects. The next example will show another implementation which will not copy objects but make them immutable instead.

 

Use immutable objects in C#

Depending on the use case it may not be necessary to create a copy. For example, if you have data which is nearly never changed, like settings parameters, you may copy this data very often but change it infrequent. That means you want to read the data often but write access is needed rarely. Such use cases can be implemented by using immutable objects. This will allow you to pass a reference to the data. But this reference will be read only. So, you can use it within your public interface. In this case you will hide the memory management even if you give information about memory addresses. That’s because the client cannot specify the memory address within input variables – internally you can use the address or create your own memory object – and the client cannot write something to memory addresses of function results. As the function results are immutable the client should create its own objects if he wants to make some changes.

The following source code shows a possible implementation.

class Person
{
  public Person(string name, int age)
  {
    mName = name;
    mAge = age;
  }

  public Person(Person person)
  {
    mName = person.mName;
    mAge = person.mAge;
  }

  public readonly string mName;
  public readonly int mAge;
}

class Employee
{
  public Employee(Person person, string phoneNumber)
  {
    mPerson = person;
    mPhoneNumber = phoneNumber;
  }

  public Person Person
  {
    get { return mPerson; }
  }

  public void PrintName()
  {
    Console.WriteLine(mPerson.mName + ", " + mPerson.mAge.ToString() + ", " + mPhoneNumber);
  }

  private readonly Person mPerson;
  private readonly string mPhoneNumber;
}

 

If you try to compile the client code you will now get compiler errors and the client must now change its implementation and create copies of the immutable objects.

class Program
{
  static void Main(string[] args)
  {
    Person person = new Person("John Doe", 32);
    string phoneNumber = "555 123456";
    Employee employee = new Employee(person, phoneNumber);

    employee.PrintName();

    person.mName = "Foo Bar";	// --> error
    person.mAge = 41;		// --> error
    phoneNumber = "555 111111";

    employee.PrintName();

    person = employee.Person;	
    person.mName = "Jane Doe";	// --> error
    person.mAge = 28;		// --> error
    phoneNumber = "555 999999";

    employee.PrintName();
  }
}

 

Base concept in C++

At next we want to change from C# to C++. To compare the possibilities within both languages we use the same example application.

But at first, we want to think about the base concept regarding memory management in objects. In C++ the developer uses explicit pointers. He allocates and releases the memory explicitly.

In C++ parameters and results are transferred as copy by default. Therefore, the solution we found in C# – pass and return copies – is the default behavior in C++. This default behavior reduces errors but it is slow for larger objects. So, we will often implement interfaces with pointers as parameters.  In C++ we have same base concepts which allow robust interfaces, even we use pointers. These concepts are: “pass by reference to const”, “const correctness” and “avoid returning handles to object internals”. If you not familiar with these concepts please look for according articles (for example within this blog) as I will use the concepts within the example application.

 

Pass copies and return copies in C++

The following code shows the example application written in C++. It also contains the client which is working with the parameters passed and returned to the employee object to manipulate the object internals.

class Person
{
public:
  Person() {}

  Person(std::string name, int age) : mName(name), mAge(age)
  {
  }

  std::string mName;
  int mAge;
};

class Employee
{
public:
  Employee() {}

  Employee(Person person, std::string phoneNumber) : mPerson(person), mPhoneNumber(phoneNumber)
  {   
  }

  Person GetPerson() { return mPerson; }

  void PrintName()
  {
    std::cout << mPerson.mName << ", " << mPerson.mAge << ", " << mPhoneNumber << std::endl;
  }

private:
  Person mPerson;
  std::string mPhoneNumber;
};

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person("John Doe", 32);
  std::string phoneNumber = "555 123456";
  Employee employee = Employee(person, phoneNumber);

  employee.PrintName();

  person.mName = "Foo Bar";
  person.mAge = 41;
  phoneNumber = "555 111111";

  employee.PrintName();

  person = employee.GetPerson();
  person.mName = "Jane Doe";
  person.mAge = 28;
  phoneNumber = "555 999999";

  employee.PrintName();

  return 0;
}

 

As C++ passes and returns copies of objects by default, the C++ example works fine.

 

Use pointers in C++

At next we want to change our example to use pointers, e.g. because the objects may be huge and the copies therefore expensive. The following example will use a smart pointer to manage the person data.

class Person
{
public:
  Person() {}

  Person(std::string name, int age) : mName(name), mAge(age)
  {
  }

  std::string mName;
  int mAge;
};

class Employee
{
public:
  Employee() {}
  
  Employee(std::shared_ptr<Person> person, std::string phoneNumber) : mPhoneNumber(phoneNumber)
  {
    mPerson = std::move(person);
  }
  
  std::shared_ptr<Person> GetPerson() { return mPerson; }

  void PrintName()
  {
    std::cout << mPerson->mName << ", " << mPerson->mAge << ", " << mPhoneNumber << std::endl;
  }

private:
  std::shared_ptr<Person> mPerson;
  std::string mPhoneNumber;
};

int _tmain(int argc, _TCHAR* argv[])
{
  std::shared_ptr<Person> person = std::make_shared<Person>("John Doe", 32);  
  std::string phoneNumber = "555 123456";
  Employee employee = Employee(person, phoneNumber);

  employee.PrintName();

  person->mName = "Foo Bar";
  person->mAge = 41;
  phoneNumber = "555 111111";

  employee.PrintName();

  person = employee.GetPerson();
  person->mName = "Jane Doe";
  person->mAge = 28;
  
  employee.PrintName();

  return 0;
}

 

If we execute the application we will now cause the same issue as in C#. The client manipulates the employee object internal data without knowing it. So, we will violate the base concept of a hidden memory management.

But wait a moment, in C++ we have the nice feature if “const correctness”. Let’s use this feature to pass and return const parameters and results. The following source code contains the previous example, extended by const-expression.

class Person
{
public:
  Person() {}

  Person(const std::string name, const int age) : mName(name), mAge(age)
  {
  }

  std::string mName;
  int mAge;
};

class Employee
{
public:
  Employee() {}

  Employee(const std::shared_ptr<Person> person, const std::string phoneNumber) : mPhoneNumber(phoneNumber)
  {
    mPerson = std::move(person);
  }

  const std::shared_ptr<Person> GetPerson() const { return mPerson; }

  void PrintName() const
  {
    std::cout << mPerson->mName << ", " << mPerson->mAge << ", " << mPhoneNumber << std::endl;
  }

private:
  std::shared_ptr<Person> mPerson;
  std::string mPhoneNumber;
};

 

Unfortunately, this changes nearly nothing. “Const correctness” is an important feature and you should design every interface with respect to this concept. But in our case, it does not solve the memory management issue. And that’s because C++ ensures a bitwise constness only. We did not change the pointer itself, so the bitwise representation of our object instance is unchanged. But we changed the content of the memory the pointer is referencing. But this logical constness cannot be checked by a compiler because it is use case specific. Therefore “Const correctness” will help us because the compiler can check the bitwise constness but as developers we should implement a logical constness ourselves because it is use case dependent.

 

Initialize with copy and return read only pointers in C++

As described above the employee object wants to hold own data and therefore had should create an own instance of the needed data and initialize it with the input parameters of the ctor. As the client does not know anything about the internal data management of the object it should pass the data as reference to const and the called object ctor itself is responsible to created data copies if needed. Getter function which contain information about internal data can create data copies too. This depends on the according use case. If copies are expensive and should be avoided, it is possible to return a const reference to some internal data. In this case the client has read only access. If the client wants to change some data of the returned object it had to create an own copy of the data.

The following source code shows a possible implementation.

class Person
{
public:
  Person() {}

  Person(std::string name, int age) : mName(name), mAge(age)
  {
  }

  std::string mName;
  int mAge;
};

class Employee
{
public:
  Employee() {}
  
  Employee(const Person& person, std::string phoneNumber) : mPhoneNumber(phoneNumber)
  {
    mPerson = std::make_shared<Person>(person);    
  }
  
  std::shared_ptr<const Person> GetPerson() { return mPerson; }

  void PrintName()
  {
    std::cout << mPerson->mName << ", " << mPerson->mAge << ", " << mPhoneNumber << std::endl;
  }

private:
  std::shared_ptr<Person> mPerson;
  std::string mPhoneNumber;
};

 

The according client code will now generate compiler errors in case the client tries to change the value of the getter directly.

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person("John Doe", 32);
  std::string phoneNumber = "555 123456";
  Employee employee = Employee(person, phoneNumber);  

  employee.PrintName();

  person.mName = "Foo Bar";
  person.mAge = 41;
  phoneNumber = "555 111111";

  employee.PrintName();

  std::shared_ptr<const Person> pPerson = employee.GetPerson();
  pPerson->mName = "Jane Doe";	// error
  pPerson->mAge = 28;		// error

  employee.PrintName();

  return 0;
}

 

 

Use immutable objects in C++

Like in C# you can make the data objects immutable. The following source code shows the adapted example application.

class Person
{
public:
  Person(std::string name, int age) : mName(name), mAge(age)
  {
  }

  const std::string mName;
  const int mAge;
};

class Employee
{
public:
  Employee() {}
  
  Employee(std::shared_ptr<Person> person, std::string phoneNumber) : mPhoneNumber(phoneNumber)
  {
    mPerson = std::move(person);
  }
  
  std::shared_ptr<Person> GetPerson() { return mPerson; }

  void PrintName()
  {
    std::cout << mPerson->mName << ", " << mPerson->mAge << ", " << mPhoneNumber << std::endl;
  }

private:
  std::shared_ptr<Person> mPerson;
  const std::string mPhoneNumber;
};

 

If the client now tries to change the input or output parameter, a compiler error will be shown. The following source code shows the client application and the four lines of codes with compiler errors.

int _tmain(int argc, _TCHAR* argv[])
{
  std::shared_ptr<Person> person = std::make_shared<Person>("John Doe", 32);  
  std::string phoneNumber = "555 123456";
  Employee employee = Employee(person, phoneNumber);

  employee.PrintName();

  person->mName = "Foo Bar";	// error
  person->mAge = 41;		// error
  phoneNumber = "555 111111";

  employee.PrintName();

  person = employee.GetPerson();
  person->mName = "Jane Doe";	// error
  person->mAge = 28;		// error
  
  employee.PrintName();

  return 0;
}

 

Use C# or C++?

At this point, I would deliberately avoid comparing the two languages. Both have a nice support for object-oriented development. Some of the concepts are equal but there are some differences too. But I think the differences regarding the object-oriented concepts are too small and therefore should never influence your choice for one of the languages. If you start a new project, the selection of the language should be driven by the environmental and quality needs and not by technical preferences. For example, you should not prefer C++ over C# because the developer likes multiple inheritance. And even the programming paradigm should be chosen with respect to the actual project. The object-oriented paradigm may not be the best choice for your project.

 

Summary

To get a high execution performance, pointers are heavily used as well in C# as in C++. In C#, they are normally used implicit and in C++ explicit. Both programming languages contain language features and concepts for object-oriented implementation. But of course, as the languages are very flexible and not limited to single programming paradigms, they cannot prevent the developer doing conceptual errors. Within this article I focused on one important concept of object-oriented development – the private memory management of objects – and introduced some possible implementations according to this concept. As this is a complex topic the article should help you to open your mind for this subject, show typical implementation errors and give you a short introduction into possible solutions.

Veröffentlicht unter C++ | Kommentar hinterlassen

Prefer non-member functions

In C++ you can write a function as member function of a class or as non-member function outside of classes. But which of this both software designs is applicable? Which one do you should prefer? The answer is easy: It depends! Within this article I want to give you some guidelines which you may use to make decisions about this software design question. This will help you in your day by day business because as software developers we will write functions every day and therefore it’s a very fundamental question where we want to place this functions: inside or outside of a class.

To think about this question we will use an easy example. Let’s say we want to implement a database access. Typical functionalities of such a database access are connection management and create, read, update and delete values. The following example shows a basic implementation.

class DatabaseConnection;
class DatabaseValue;

namespace Database
{
  class DatabaseAccess
  {
  public:
    void Connect(std::string connectionSettings);
    void Disconnect();

    void InsertValue(std::string sqlQuery);
    DatabaseValue ReadValue(std::string sqlQuery);
    void UpdateValue(std::string sqlQuery);
    void DeleteValue(std::string sqlQuery);

  private:
    DatabaseConnection mConnection;
  };
}

I have implemented all functions as member functions inside of a class. Why did I choose this software design? It is also possible to write non-member functions instead.

namespace Database
{
  DatabaseConnection Connect(std::string connectionSettings);
  void Disconnect(DatabaseConnection connection);

  void InsertValue(DatabaseConnection connection, std::string sqlQuery);
  DatabaseValue ReadValue(DatabaseConnection connection, std::string sqlQuery);
  void UpdateValue(DatabaseConnection connection, std::string sqlQuery);
  void DeleteValue(DatabaseConnection connection, std::string sqlQuery);
}

As you can see, all functions share a common data member, the database connection object. If you use non-member functions you have to hand around this connection object, or even worse, you have to use a global variable. Therefore this use case is a perfect candidate for a class with member functions. The class will have its internal data and resource management which will be used by the member functions. And it will have the public interface with the member functions a client needs to implement database functionalities.

After implementation of this class you will use it within client. At this moment you may see that most of the clients will have a few database accesses only and most often read single values. Therefore we now have the need for a function which establish a database connection, read the value and closes the connection. You may add this function to the existing database class or write a non-member function. The following source code shows both implementations.

namespace Database
{
  class DatabaseAccess
  {
  public:
    void Connect(std::string connectionSettings);
    void Disconnect();

    void InsertValue(std::string sqlQuery);
    DatabaseValue ReadValue(std::string sqlQuery);
    void UpdateValue(std::string sqlQuery);
    void DeleteValue(std::string sqlQuery);

    // member function
    DatabaseValue ReadSingleValue(std::string connectionSettings, std::string sqlQuery)
    {
      DatabaseValue dbValue;
      DatabaseAccess dbAccess = DatabaseAccess();

      dbAccess.Connect(connectionSettings);
      dbValue = dbAccess.ReadValue(sqlQuery);
      dbAccess.Disconnect();

      return dbValue;
    }

  private:
    DatabaseConnection mDatabaseConnection;
  };

  // non-member function
  DatabaseValue ReadSingleValue(std::string connectionSettings, std::string sqlQuery)
  {
    DatabaseValue dbValue;
    DatabaseAccess dbAccess = DatabaseAccess();

    dbAccess.Connect(connectionSettings);
    dbValue = dbAccess.ReadValue(sqlQuery);
    dbAccess.Disconnect();

    return dbValue;
  }
}

What do you think is the better solution? Implement the method as member function or as non-member function?

I think this method should not be a member of the class. There are several reasons for my opinion. At first, the method adds a new concept to the class which does not fit into the existing interface. The existing interface is based on a connection which you have to establish and close and several database access functions you may use between opening and closing of the connection. The new function has a completely new functionality which is independent of the existing ones. It needs an own connection settings string and maybe it will result in errors if you already called the connect-function. So this new function does not fit into the existing interface and therefore makes the class harder to use for a client.

Another important aspect is the implementation of the function. As you can see we don’t use the class internal members within the function. This is a strong indication for the guess that the function should not part of the class.

Therefore I prefer to implement this method as non-member function. The method is strongly connected with the database access class because both belong to the same group of functionalities. But it is not part of the database access class itself because it does not extend the class functionality. It adds a new group of functionalities instead.

Non-member functions and classes which belong to the same topic can be grouped within the same namespace. Like in this example they all belong to the group of database specific functionalities and therefore I have grouped them together within the Database namespace.

Guidelines for non-member functions

After this comparison between member functions and non-member functions I want to think about some important aspects of non-member functions. At the beginning of this article I wrote a class and within the next code example I just take the class methods and put them outside of the class as non-member functions. But this is dangerous and create hard to maintain and error-prone code. That’s because these functions are non-member functions from a technical point of view but not from a logical point of view. They all belong together, can only be called in the right order and may have side effects or must hand around resources.

Therefore I want to talk about some guidelines you should take in mind whenever you write a non-member function. From my point of view a non-member function respect the following aspects:

  • Atomic
  • Stateless
  • Without side effects

A function is atomic if it can be executed without the need of other functions. Within the above source code with the database functions as non-members, the functions depend on each other. You have to call the Connect function first before you can use the Insert, Read, Update and Delete functions. And at the end you must not forget to call the Disconnect function. So these functions have a strong relationship. You cannot use o of the functions you always have to use the right combination of several functions.

If you have such an atomic function, it should be stateless. Sometimes stateless functions are also called service functions. It means that if you call the function with the same parameters several times it will always return the same result independent of the state of the application or the system where it is executed. For example you may try to break up the strong relationship between the database non-member functions and put the database connection into a global variable to remove the need for the data turn around. In this case the relationship between the functions will be reduced. But of course you are far away from atomic functions and add a global variable which results in some other issues. But if you do so your functions will become state-controlled. For example the Read-function has a SQL-query as input and return the database value. But their functionality is state-controlled now as it will check the state of the database connection, which is now stored within the global variable. If the connection is established the function will return the result of the SQL-query, otherwise it may throw an exception. The non-member function will now become a state-controlled non-service function.

Another very important aspect is the question whether the function has side effects or not. Maybe that’s the most important of the three aspects because if it is not fulfilled it can result in big issues and make the source code very hard to maintain and error-prone. To have a function without side-effects, the function should not change anything within your software system. So, for example, it should not write into a global variable, should not set some application property and it should not create any kind of output file. This may surprise you as we have implemented a database non-member function which will read one value from the database and you may now think what if we want to write one value? Is it bad style if we put this in a non-member function? Furthermore the last example that we don’t want to create some kind of output file may be surprising too as many of the non-member functions are implemented especially fur such helper or tool methods. You are right if you think about the functionality of this non-member function. But there are huge differences if we think about the two main possibilities how we can implement this functionality. For example if you have a data object and you want to serialize into a file in xml format. You may implement this within a non-member function. This will contravene the guideline that a non-member function shall not have any side effects because in this case we create a file and therefore change out system. So think about the other possibility and put all functionality with side effects into a class. This will be a good idea anyway because “side effect” always means that we have to access some resource. And resource management is one of the main reasons why we have classes. Going back to the serialization example in my opinion it will be a good design to implement a File management class which does the generic file handling without analyzing the file content. The de/serialization of the data, which means converting an object into an xml stream and vise verse, will be implemented within a second class. If we have these two classes we can create our non-member function which writes an object into the file. This non-member function will use both classes and combine their features to create the output file. Of course this will create a file and therefore has a side effect, but the big difference between the direct implementation of the file writer within the non-member function is that the non-member function itself will not create the file and therefore it is not the source for the side effects. It will delegate this functionality to the according experts, in this case the classes which are responsible for the resource management.

The long explanation of the last topic and the small difference between own responsibility for side effects versus delegated responsibility for side effects shows the small difference of these concepts from an implementation point of view. Developers may even argue that they want to create the file directly within the non-member function and avoid the overhead and implement additional classes. But if you have to understand, maintain or extend such source code or if you have to hear user complaints about application errors and you have to write bugfixes based on function with side effects, you will understand why I think that this aspect is so important.

Do not put everything in the class

Within the previous paragraph I addressed an interesting aspect: a non-member function can use one or more classes to fulfill its functionality. I even think that this is the standard use case. An interesting case in this context is a function which uses member functions of one class. Such functions are often implemented. This is understandable because if you implement a class and you want to add some functionality based on the class it feels self-evident to put this function into the class. But as we have seen so far some of these functions are good candidates for non-member functions. Fortunately there is a really easy characteristic to recognize such functions. If a function will use the public interface functions of the class only, it is a perfect candidate for a non-member function. So if you write a class and their member functions you may ask yourself: Does this class use the internal members and resource handling or does it only use the public interface functions? In the first case it should be implemented as class member function and in the second case as non-member function.

Advantages of non-member functions

So far we have seen use cases and guidelines when and how we can implement non-member functions. But why should we implement them at all? We could also put them together into a class. In our example the function to read a single database value can be grouped together with some other database tool functions and we can put them into a database tool or helper class. And if you look into existing code you will sometimes find a lot of “helper”, “tool” or “common” classes.

If we implement the non-member functions as atomic functions without side effects we don’t have any advantage if we put them together in one class. There is no relationship between the functions, except that they belong together from a logical point of view. But we can respect this aspect by putting them into the same namespace and there is no need to put them into a class and therefore connect them in a technical way.

If we leave them disconnected we have less dependency. The client which uses the functions depends on this function only. As a result only a change of the function will result in the need to adapt the client. If we put several functions into one class we increase the probability for changes. Clients will now use the function of the class and therefore they may depend on the class and must be changed or re-compiled every time the class changes, which will of course occur more often then a change of a single function. By using non-member functions we will increase the independence of the function as we create fewer dependencies to clients.

The same aspect will be relevant if we want to add new functionality. In case we have non-member functions we can add new functionality at any time as this will not affect the clients. In contrast, if we add something to a class it may become necessary to update or recompile the client code. By using non-member functions we facilitate the implementation of new functionality.

The atomicity of non-member function will allow us to group them together as we want. We can use one common namespace for all non-member functions or several sub-namespaces with one common parent namespace or any kind of namespace structure. Furthermore we can put these function groups into several files. So we can create functions packages and deploy them independently. By using classes or a system of parent classes and sub classes you may be able to create the same grouping for the functions but it will become more complex and less maintainable then using namespaces. And with classes you don’t have the possibility to split functions of the same group into different files and deploy them separated. You can use the same namespace in different files but you cannot write partial classes in different files. By using non-member functions can group functions in an easy manner and you are able to create and deploy function packages.

Summary

Member functions of classes as well as non-member functions have their own advantages and disadvantages. If you want to benefit of these advantages you have to choose the right kind of function depending on your use case.

If you want to write functions which are strongly coupled as they share the same resources and will be used together by a client you should implement an according class and write class member functions.

If you have atomic functions which do not share or need any resources and can be executed as service-functions without any side effects, you should implement these methods as non-member functions. Several non-member functions which belong to the same topic can be grouped within one namespace.

Veröffentlicht unter C++ | Kommentar hinterlassen

Returning handles to private members makes them public

Some key features of object-oriented programming can be brunch together to something I want to call the “black box idea”. An object is a black box offering a public interface. All internal implementations, like state management, data control and resource management are not visible to the client. That’s why we implement a public interface and private class members.

Within this article I want to think about the question whether we can return handles to class internal members with respect to the black box idea or whether this will violate the object oriented principles.

At first we will create a small example application which we will later on use to test several possibilities to return handles. Within the example we have a class “Person” which should manage person specific data. The data is stored in a struct and the person class will have an internal member with an instance of this struct. Within this example the struct contains the name and address of the person. Both elements are implemented as structs too. Furthermore for testing purposes we add some functionality to the person class. Within the ctor we create the person data and we add a method which writes the person name to the console.

struct Name
{
  std::string FirstName;
  std::string LastName;
};

struct Address
{
  std::string City;
  std::string Street;
};

struct PersonData
{
  Name mName;
  Address mAddress;
};

class Person
{
public:
  Person()
  {
    mPersonData = std::make_shared<PersonData>();
    mPersonData->mName.FirstName = "John";
    mPersonData->mName.LastName = "Doe";
    mPersonData->mAddress.City = "Springfield";
    mPersonData->mAddress.Street = "Main Street";
  }

  void ShowName()
  {
    std::cout << mPersonData->mName.FirstName << " " << mPersonData->mName.LastName << std::endl;
  }

private:
  std::shared_ptr<PersonData> mPersonData;
};

 

We will use this implementation for all following examples. To make the examples clearer I don’t want to show the whole source code every time. Therefore the next examples show an excerpt of the people class only, with additional methods we want to implement. Soo keep in mind that we always have the ctor which create the people data and the ShowName method which prints the name to the console.

 

Returning handle

The issue of this article is the question whether returning a handle to an internal member is possible without the risk to violate object oriented concepts. So we will start to an according method to the people class. Let’s say we want to get the name of the person. Therefore we return a handle to the according data member.

class Person
{
public:
  ...

  Name& GetName() { return mPersonData->mName; }

  ...
};

 

Within a client application we can use this method and get the name of the person. But this software design has a big disadvantage. The client will also get the possibility to change the object internal member, without knowing it or on purpose. The following code shows an according example. The client can set the name of the data object he received and if we call the ShowPerson method we will see that the class internal member was changed too.

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person();
  person.ShowName();

  person.GetName().LastName = "Smith";
  person.ShowName();

  return 0;
}

 

By returning a handle to the internal member we make this member public. If we disclosure class internal details we will violate the object oriented concepts and create error-prone code. So we create a private member which is public on closer inspection. Unfortunately the compiler will not detect such unsafe implementations and therefore we do not get a compiler warning.

 

Const function

Constness is a strong and important C++ feature. By making a method const we will ensure that this method cannot change class internal members. That’s exactly what we want. So let’s make the method const and try again whether we can change the internal member.

class Person
{
public:
  ...

  Name& const GetName() { return mPersonData->mName; }

  ...
};

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person();
  person.ShowName();

  person.GetName().LastName = "Smith";
  person.ShowName();

  return 0;
}

 

Unfortunately this has no effect. We can compile and execute the code and the internal member can still be changed. Is there something wrong with the const feature? No, everything is fine as we don’t change the person object. The person object stores the data by using a pointer to the person data object. By calling the GetName method we get this pointer and change the data. So the pointer itself will not be changed and the bitwise constness of the person object is guaranteed. As a result, from a compiler point of view this code is fine. From a user point of view we see that we have ignored the logical constness of the object but that’s something the compiler cannot detect.

 

Const handle

Another possibility may be to make the returned handle itself const. If we do so we have a read only handle and cannot change the internal member anymore. So let’s try this possibility.

class Person
{
public:
  ...

  const Name& const GetName() { return mPersonData->mName; }  

  ...
};

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person();
  person.ShowName();

  person.GetName().LastName = "Smith";  // compilation error
  person.ShowName();

  return 0;
}

 

This change seems to work. We will now get a compiler error and cannot change the data object anymore. As conclusion this seems to be an easy solution for our issue. Just make the object handle read only and we cannot change it by mistake or on purpose.

But unfortunately there is another issue which can result in error-prone code and instable applications. We will now have read access to an object which is managed by the person class. And the person class thinks that this data object is one its private members. So the person class can change, invalidate and delete the data object and the underlying memory without respect of any existing client.

The following source code shows an according example. For test purposes I have created an Invalidate-method which resets the data object. This method is for test purposes only. Such a reset of the internal member can occur at any time as the person object can change its internal state whenever needed.

class Person
{
public:
  ...

  const Name& const GetName() { return mPersonData->mName; }  

  void Invalidate()
  {
    mPersonData.reset();
  }

  ...
};

int _tmain(int argc, _TCHAR* argv[])
{
  Person person = Person();
  person.ShowName();

  // get handle to the name object
  const Name* pName = &(person.GetName());

  // invalidate the internal member
  // such a reset can be done internally within the person object 
  // or it may be triggered by another thread or...
  person.Invalidate();

  // try to access the name handle data
  std::cout << pName->LastName;   // error during runtime

  return 0;
}

 

If we execute the test application we will get an error during runtime. We try to access the data member “pName->LastName;“  but the pointer to the data object is invalid and therefore we get an according exception.

Returning a handle is dangerous, even if it is a const one. This conclusion can be used as general guideline. Of course there may be exceptions to this rule but as a general guideline you shall keep in mind to not return handles.

If you have to make an exception to this rule, for example to create resource or speed optimized core components for your application or framework, you should minimize the chance for errors. In such a case you should use the according interface in a small and defined internal scope only. You should not return handles within an interface which is used by external clients. And of course you have to add according source code documentation explaining how to use the code and the risk in case this code is not used as intended.

 

Summary

Avoid returning handles to object internals.  To keep internal members private increases encapsulation and helps to write robust and clean code.

Veröffentlicht unter C++ | Kommentar hinterlassen

Design patterns: Command

The Command design pattern encapsulates a request as an object. This will allow adding additional functionality to the request. A typical example is the undo/redo functionality.

The command object will be used as mediator between the client and the receiver and ads its additional behavior. For example we could have a calculator application. The client will do some calculation by requesting the according functions of the receiver, in this case a calculation object. If we want to implement undo/redo functions, we could now add an according command object. The client will call the command instead of the calculator methods. The command itself will call the calculator methods. And it offers additional behaviors like the undo/redo functionality.

The following example will show a possible implementation of this pattern. At first we implement the client and the receiver for the calculator example. So let’s start by defining the interface for the calculator.

enum Operation
{
    Summation,
    Subtraction,
    Multiplication,
    Division
}

interface ICalculator
{
    int ExecuteOperation(Operation operation, int operand);
}

At next we implement the calculator.

class Calculator : ICalculator
{
    private int _currentValue = 0;

    public int ExecuteOperation(Operation operation, int operand)
    {
        switch (operation)
        {
            case Operation.Summation: _currentValue = _currentValue + operand; break;
            case Operation.Subtraction: _currentValue = _currentValue - operand; break;
            case Operation.Multiplication: _currentValue = _currentValue * operand; break;
            case Operation.Division: _currentValue = _currentValue / operand; break;
            default: throw new ArgumentException();
        }

        return _currentValue;
    }
}

And we use the implemented calculator within a console application.

static void Main(string[] args)
{
    ICalculator calculator = new Calculator();

    Console.WriteLine("+ 2 = " + calculator.ExecuteOperation(Operation.Summation, 2));
    Console.WriteLine("* 5 = " + calculator.ExecuteOperation(Operation.Multiplication, 5));
    Console.WriteLine("- 3 = " + calculator.ExecuteOperation(Operation.Subtraction, 3));

    Console.ReadKey();
}

Now we want to add undo/redo features. This can be done by using the command design pattern. So we want to add a calculator command which offers a undo function. We don’t need an explicit redo function as a redo is equal to a repeated execution of the command.

interface ICalculatorCommand
{
    int ExecuteOperation();
    int UndoOperation();
}

The command itself is implemented by using the calculator object. It will redirect the client calls to the calculator and adds the undo function.

class CalculatorCommand : ICalculatorCommand
{
    private ICalculator _calculator;
    private Operation _operation;
    private int _operand;

    public CalculatorCommand(
        ICalculator calculator,
        Operation operation,
        int operand)
    {
        _calculator = calculator;
        _operation = operation;
        _operand = operand;
    }

    public int ExecuteOperation()
    {
        return _calculator.ExecuteOperation(_operation, _operand);
    }

    public int UndoOperation()
    {
        Operation undoOperation = GetUndoOperation();

        return _calculator.ExecuteOperation(undoOperation, _operand);
    }

    private Operation GetUndoOperation()
    {
        switch (_operation)
        {
            case Operation.Summation: return Operation.Subtraction;
            case Operation.Subtraction: return Operation.Summation;
            case Operation.Multiplication: return Operation.Division;
            case Operation.Division: return Operation.Multiplication;
            default: throw new ArgumentException();
        }            
    }
}

The client, in our example the console application, will now have the possibility to store the calculation command. This will allow adding unlimited undo and redoing steps. In this example we undo and redo the last two calculations.

static void Main(string[] args)
{
    ICalculator calculator = new Calculator();
    ICalculatorCommand command;
    List<ICalculatorCommand> commands = new List<ICalculatorCommand>();

    command = new CalculatorCommand(calculator, Operation.Summation, 2);
    Console.WriteLine("+ 2 = " + command.ExecuteOperation());
    commands.Add(command);

    command = new CalculatorCommand(calculator, Operation.Multiplication, 5);
    Console.WriteLine("* 5 = " + command.ExecuteOperation());
    commands.Add(command);

    command = new CalculatorCommand(calculator, Operation.Subtraction, 3);
    Console.WriteLine("- 3 = " + command.ExecuteOperation());
    commands.Add(command);

    //undo last two command
    Console.WriteLine("undo = " + commands[2].UndoOperation());
    Console.WriteLine("undo = " + commands[1].UndoOperation());

    //undo last two command
    Console.WriteLine("redo = " + commands[1].ExecuteOperation());
    Console.WriteLine("redo = " + commands[2].ExecuteOperation());

    Console.ReadKey();
}
Veröffentlicht unter .NET, C#, Design Pattern | Kommentar hinterlassen