Understanding C++ Classes (UCC)

The concept of class in C++ is exactly the same as what you have learned in chapter 8. This concept is derived from the object-oriented programming paradigm that has been presented in that chapter. If you have understood the concept of object-oriented programming and class programming in Java well, then the concept of class in C++ is not a difficult matter. You need to know, Java takes most of the C++ programming concepts (including classes) to be applied. The main difference may only be in the writing syntax. In this chapter the concept of object-oriented programming will not be discussed again, but will go directly to its application in C++.

1. Class Declaration 

Just like in Java, class creation in C++ uses the class keyword. In the class there are data and methods that will be used by objects that will be created (instances) of the class. This data and methods are usually called class members. Methods in C++ are the same as the functions that you have learned in the previous sub-chapter. Consider the following example.

Example 9.26. Class declaration and usage

#include <iostream> using namespace std;

class PersegiPanjang {     int x, y;   public:     void set_nilai (int,int);     int luas() {return (x*y);}
};
void PersegiPanjang::set_nilai (int a, int b) {   x = a;   y = b;
}
int main () {
  PersegiPanjang pp1, pp2;   pp1.set_nilai (3,4);   pp2.set_nilai (7,12);
  cout << "Luas pp1 : " << pp1.luas()<<endl;   cout << "Luas pp2 : " << pp2.luas()<<endl;   return 0; }

In the example above, the class we declared is called Rectangle and has two class members, namely x and y, and two methods, namely set_nilai and luas(). The two methods are set to have public access. Like Java, there are 3 access rights to data or methods in a class, namely public, private and protected. Public means that the class member can be accessed from outside the class. Private means that the class member can only be accessed within the class. While protected means that the class member can be accessed by a subclass of the class, but not by a part outside the class.

The set_nilai method has two arguments/parameters that are both of the int data type but do not return a value, so we use the void keyword. The luas() method has no arguments but does return a value. For methods that return a value, we use the data type in front of the method name. Revisit chapter 8 to recall arguments in methods.

In C++ we can implement methods inside or outside the class, but the method declaration must be inside the class. Generally we put the method implementation outside the class (outside the { } sign). Look at the example above. The declaration of the set_nilai method is inside the Rectangle class but its implementation is outside the class. While the luas() method, both the declaration and implementation are inside the class. In the implementation of the method outside the class we use the :: sign to define class members outside the class (note the line 

void PersegiPanjang::set_nilai (int a, int b))

After the class is created we can use it by creating an object that is an instance of the class. Pay attention to the part that begins with int main(). In this part we create two objects named pp1 and pp2 as instances of the Rectangle class. Then we use these objects to call the set_nilai and luas() methods of the Rectangle class. Type the program above and then run it. What are the results?

As in Java, generally a class will have a constructor that is used to initialize variables or allocate memory. This constructor has the same name as its class. A destructor method should also be created in a class. A destructor is the opposite of a constructor. Its main purpose is to return the variable value to its initial form and free memory from the use of the variable. The destructor method has the same name as the class name, but with the addition of the ~ sign. Consider the following examples of constructor and destructor usage.

Example 9.27. Constructors and destructors

#include <iostream> using namespace std;

class PersegiPanjang {     int *panjang, *lebar;   public:
    PersegiPanjang (int,int);
    ~PersegiPanjang ();
    int luas () {return (*panjang * *lebar);}
};

PersegiPanjang::PersegiPanjang (int a, int b) {   panjang = new int;   lebar = new int;   *panjang = a;
  *lebar = b;
}

PersegiPanjang::~PersegiPanjang () {   delete panjang;   delete lebar;
}
int main () {
  PersegiPanjang pp1 (3,4), pp2 (5,6);   cout << "Luas pp1: " << pp1.luas() << endl;   cout << "Luas pp2: " << pp2.luas() << endl;   return 0; }

2. Inheritance 

C++ also provides inheritance facilities in classes. The inheritance process in C++ is somewhat more complicated compared to Java. This is because C++ provides the possibility of inheritance with consideration of access rights. There are two access rights in superclass inheritance to subclass, namely public and private.

If a class is derived as public from its superclass then the conditions are as follows:

  • Public parts in the superclass will remain public in the subclass.
  • Protected parts in the superclass will remain protected in its subclasses.   
  • Private parts in the superclass will not be accessible by the subclass.

If a class is derived as private from its superclass then the conditions are as follows:

  • The public parts in the superclass will become private in the subclass.
  • The protected part in the superclass will be private in its subclass.   
  • Private parts in the superclass will not be accessible by the subclass. 
  • Consider the following example.

Example 9.28. Inheritance

#include <iostream> using namespace std;
 class CPolygon {   protected:
    int width, height;   public:     void set_values (int a, int b)
      { width=a; height=b;}
  };
class CRectangle: public CPolygon {   public:
    int area ()
      { return (width * height); }
  };
class CTriangle: public CPolygon {   public:
    int area ()
      { return (width * height / 2); }
  };    int main () {   CRectangle rect;   CTriangle trgl;   rect.set_values (4,5);   trgl.set_values (4,5);   cout << rect.area() << endl;   cout << trgl.area() << endl;   return 0; }

In the program code above, CPolygon is the superclass, while CRectangle and CTriangle are subclasses. In the CPolygon class, the width and height variables are declared as protected, because they are intended to be accessed by their subclasses only. In addition, this class also has a set_values ​​method. Both variables and methods will be inherited by their subclasses, namely CRectangle and CTriangle. Note how CRectangle and CTriangle are declared as derived classes of CPolygon using the public keyword. Now try changing the word public in the CTriangle class declaration so that it becomes class CTriangle: private CPolygon. If you compile, you will encounter the following error message:

Compiling source file(s)...
oo-test.cpp oo-test.cpp: In function `int main()':
oo-test.cpp:9: error: `void CPolygon::set_values(int, int)' is inaccessible
oo-test.cpp:28: error: within this context
oo-test.cpp:28: error: `CPolygon' is not an accessible base of `CTriangle'

Why can a compilation error occur? This is because the above rule applies. The set_values ​​method in the CPolygon class is declared public, but is passed down to the CTriangle class with private. This will change the method from public to private when it is in the CTriangle class. Of course you remember that if a class member is given private access rights, it cannot be accessed from the outside.

3. Polymorphism

In C++, to be able to implement polymorphism, we need to use a special function known as a virtual function. We put this function in the superclass, then we can redefine the function in the subclass. Consider the following example.

Example 9.29. Using virtual functions

#include <iostream>

using namespace std;

class AnggotaSekolah {   char* nama;   char* alamat; public:   void SetNama(char* N) {      nama = N;   }
  void SetAlamat(char* A) {      alamat = A;
  }   char* GetNama() {      return nama;
  }
  char* GetAlamat() {      return alamat;
  }
  // Membuat fungsi virtual   virtual void Bekerja() {      cout<<"Bekerja"<<endl;
  }
  virtual void Berpakaian() {      cout<<"Berpakaian"<<endl;
  }
};
class Siswa: public AnggotaSekolah {   char* Jurusan;   char* Program;
  int semester; public:   void SetJurusan(char* J) {
     Jurusan = J;   }
  void SetProgram(char* P) {
    Program = P;   }
  void SetSemester(int smt) {     semester = smt;
  }   char* GetJurusan() {      return Jurusan;
  }   char* GetProgram() {      return Program;
  }   int GetSemester() {      return semester;
  }
  // override pada fungsi Bekerja   void Bekerja() {
     cout<<"Bekerja menuntut ilmu"<<endl;
  }
  // override pada fungsi Berpakaian   void Berpakaian() {
     cout<<"Berpakaian seragam putih abu-abu"<<endl;
  }
};
class Guru: public AnggotaSekolah {   char* jabatan;   char* keahlian; public:   void SetJabatan(char* jbt) {      jabatan = jbt;
  }
  void SetKeahlian(char* khl) {      keahlian = khl;
  }   char* GetJabatan() {      return jabatan;
  }   char* GetKeahlian() {      return keahlian;
  }
  // override pada fungsi Bekerja   void Bekerja() {
     cout<<"Bekerja mengajarkan ilmu"<<endl;
  }
  // override pada fungsi Berpakaian
  void Berpakaian() {
     cout<<"Berpakaian baju seragam dinas resmi"<<endl;
  }
};

// Fungsi utama int main() {

  // instansiasi pada kelas AnggotaSekolah, Siswa dan Guru
  AnggotaSekolah As;
  Siswa Sw;
  Guru Gr;

  // Memanggil fungsi Bekerja dari masing-masing kelas
  cout<<"Anggota sekolah sedang ";   As.Bekerja();   cout<<"Siswa sedang ";   Sw.Bekerja();   cout<<"Guru sedang ";   Gr.Bekerja();   cout<<'\n';

  // Memanggil fungsi Berpakaian dari masing-masing kelas
  cout<<"Anggota sekolah harus ";   As.Berpakaian();   cout<<"Siswa harus ";   Sw.Berpakaian();   cout<<"Guru harus ";
  Gr.Berpakaian();
   return 0; }

In the program code above, there are two virtual functions/methods, namely Kerja and Berpakakan. These are the methods that we will use in the subclass but with different implementations. Pay attention to the contents of each method in each subclass. This method is commonly referred to as overriding. Try going back to chapter 8 to clarify the meaning of overriding. Also compare how overriding is done in Java and C++. If the program above is run, the results will appear as in Figure 9.9. Overloading can also be done on virtual functions. You certainly still remember the difference between overriding and overloading that has been explained in chapter 8.

Figure 9.9. Results of virtual function execution and overriding
Figure 9.9. Results of virtual function execution and overriding

In example 9.29 above, the virtual function is created complete with the contents of the function. However, C++ also provides a pure virtual function that only has a function declaration but no contents. This concept is similar to when you learned about interfaces in Java. This pure virtual function will then have its contents translated into classes that are derived from the class. The advantage of using this pure virtual function is our freedom to define these functions in their derived classes. Pure virtual functions are usually used in abstract classes. An abstract class is a class that has at least one pure virtual function. Because it is still abstract, we are not allowed to create objects directly from the abstract class.

The concept of polymorphism in C++ is structured based on the understanding of virtual functions, pure virtual functions, overriding, overloading, and abstract classes. Consider the following examples of polymorphism.

Example 9.30. Application of polymorphism

#include <iostream> using namespace std;
 class CPolygon {   protected:
    int width, height;   public:     void set_values (int a, int b)       { width=a; height=b; }
    virtual int area (void) =0; //fungsi virtual murni     void printarea (void)
      { cout << this->area() << endl; }
  };
class CRectangle: public CPolygon {   public:
    // overriding fungsi area     int area (void)
      { return (width * height); }
  };
class CTriangle: public CPolygon {   public:
    // overriding fungsi area     int area (void)
      { return (width * height / 2); }
  };
int main () {   CRectangle rect;
  CTriangle trgl;
  CPolygon *ppoly1 = &rect;  // mendefinisikan obyek pointer
  CPolygon *ppoly2 = &trgl;  // mendefinisikan obyek pointer
  ppoly1->set_values (4,5);   ppoly2->set_values (4,5);   ppoly1->printarea();   ppoly2->printarea();   return 0; }

In the example above, the CPolygon class is an abstract class that has a pure virtual function, namely area. Note how to declare a pure virtual function on the line that begins with the virtual statement. This function is not created with content but is created with the sign = 0. We cannot create objects directly from this CPolygon class. But we can create a pointer object to allocate memory based on this class. The CPolygon class also uses the keyword this. This keyword functions to point to the class itself. The statement this->area() in the code above has the same meaning as CPolygon->area(). So this statement has the same meaning as calling the virtual function area in that class.

In the code above, two pointer variables *ppoly1 and *ppoly2 are created whose values ​​are the same as the values ​​of the addresses of the rect and trgl variables. Pay close attention to the use of the * and & signs to refer to memory addresses. Run the program above and observe the results.

Other Version Notes

C++ programming requires a sufficient understanding to translate design into implementation, especially for designs that use class abstraction. The discussion focuses on the aspect of object formation (construction) of a class, and the reverse process when the object is no longer used (destruction).

1. Declaration and Definition

Declaration and definition are the first steps in every program writing, including in C++. Declaration and definition are required for all data types including user-defined types.

The simple form of class declaration is as follows,

class C { }; atau struct C { };

In the C++ language, structs and classes have the same meaning. Class declarations with structs have members with public access unless stated otherwise.

struct C {    int i;
   void f();
}

class C { public:    int i;
   void f();
}

Both declarations have the same meaning.

This was a design choice made by the designer of C++ (Bjarne Stroustrup) to use C as the basis for C++ rather than creating an entirely new language. Of course there are consequences to this design choice, one example being compatibility with the C language.

In C language declaration,

struct C { ... };

Declare C as a tag name. Tag names are different from type names, so C (tag name) cannot be used in a declaration that requires C as an object type. Both of the following declaration examples are invalid in C,

C c;     /* error, C adalah nama tag */
C *pc;   /* error, C adalah nama tag */

In C language, both declarations should be written as follows,

struct C c; struct C *pc;

Or use typedef as follows,

struct C { ... }; typedef struct C C;
C c;
C *pc;

C++ treats class names, C as tag names as well as type names and can be used in declarations. The word class can still be used in declarations, as in the following example,

class C c;

Thus C++ does not distinguish between tag names and class names, at least from a programmer's perspective, and still accepts structure declarations as in C. C++'s compatibility with tag names is not limited to the difference between tag names and type names, because the C++ standard still needs to define POD (Plain Old Data) types. POD types have many similarities to structures in C. The C++ standard defines a POD type as an object of a class that has no userdefined constructor, no protected or private members, no base class, and no virtual functions.

In the design of an application consists of many classes, and each class does not stand alone but rather depends on or relates to each other. One example of such a relationship is the relationship between one class and one or more base classes or parent classes. If class C has a base class B, known as inheritance, then the class declaration becomes,

class C : public B {}; atau class C : protected B {}; atau class C : private B {};

Access to members of base class B can be public, protected, or private, or referred to as public, protected or private inheritance. Class C is referred to as a derived class. If the access form is not stated explicitly, as in the following declaration:

class C : B

then the interpretation is private inheritance (default), but if you use a struct then it is still public inheritance.

If the designer of class C wants a multiple inheritance (MI) relationship between classes B and A, then the declaration of class C becomes,

class C : public B, public A { };

A class, like class C, has members in the form of data and functions (member functions). The contents of the class are between brackets { } and are sorted according to the access restrictions determined by the designer of the class.

class C : public B
{  public:
   (explicit) C()(:member-initializer);
   C(const C& );
   C& operator=(const C&);

   (virtual)~C();    statement lain
 (protected: statement)
 (private: statement)
};

In summary, access restrictions (access specifiers) have the meaning as shown in the following table,

| Batasan Akses | Arti                                           |
|---------------|------------------------------------------------|
| public        | Semua class atau bebas                         |
| protected     | Class itu sendiri, friend, atau derived class  |
| private       | Class itu sendiri, friend                      |

A class can grant permission for another class to access protected or private parts of the class through a friendship relationship (declared with the friend keyword).

A class has several special functions, namely constructor, copy constructor, destructor and copy assignment operator.

2. Constructor 

C() is a class member whose job is to initialize objects (instances) of a class C. The constructor has the same name as the class name, and does not have a return value. A class can have more than one constructor. A constructor that has no arguments is called a default constructor, whereas a constructor that has more than one argument is a non-default constructor. A constructor with one default argument is still a default constructor, 

class C { public:
   C(int count=10) : _count(count) {}
... private:
   int _count;
};

The C++ compiler can add a default constructor if necessary, if in the class definition:

  • there is no explicit default constructor written and no other constructor declaration (copy constructor).
  • There are no class members in the form of const data or references.

For example, the definition of class C is as follows,

class C {...};

C c1;    // memerlukan default constructor
C c2(c1);   // memerlukan copy constructor

The C++ compiler decides to add default and copy constructors after encountering these two lines of code, so the class definition effectively becomes as follows,

class C { public:
   C();               // default costructor
   C(const C& rhs);   // copy constructor

   ~C();              // destructor     C& operator=(const C& rhs);   // assignment operator
   C* operator&();    // address-of operator    const C* operator&(const C& rhs) const;
};

The compiler adds public constructors, and destructors. In addition, the compiler also adds assignment operators and address-of operators. Constructors (default and non-default) do not have to have public access, for example the Singleton design pattern.

class Singleton
{ public:
   static Singleton* instance(); protected:    Singleton(); private:    static Singleton* _instance;
};

Singleton objects (instances) are not created through constructors but through instance functions. No other singleton objects can be created if one singleton object already exists.

Generally, the compiler-generated default constructor uses the default constructor of class-type members, while ordinary members (builtin types) are not initialized. Likewise, with objects formed from other objects (copy), the compiler-generated copy constructor uses the copy constructor of class-type members during initialization. For example, the following C class declaration,

class C { public:
   C(const char* aName);
   C(const string& aName);
... private:
   std::string name;
};

The compiler-built copy constructor uses the class string copy constructor to initialize the name of aName. If the C class does not have a constructor, the compiler also adds a default constructor to initialize the name using the class string default constructor.

Object initialization using a constructor (non-default) can be done with a member initializer or with assignment as follows,

member initialization
assignment

class C {    int i,j; public:
   C() : i(0),j(1) {}
...
};

class C {    int i,j public:    C()    {
      i=0;j=0;
   }
...
};

Both methods give the same result, there is no significant difference between the two methods for non-class type data. The member initializer method is absolutely necessary for const and reference data, such as the following two examples:

class C //:1
{ public:
   C(int hi,int lo) : _hi(hi),_lo(lo) {}
... private:    const int _hi,_lo;   // const member
};

class C //:2
{ public:
   C(const string& aName) : name(aName) {}
... private:    std::string& name;   // reference member
};

The way member initialization should be done for class type members (userdefined type) as shown in the following example,

class C { public:
   C(const string& aName) : name(aName) { } private:
   std::string name;   // bukan reference member
};

The consideration of using the member initialization method lies in the efficiency of program execution. This is related to the way C++ works, which forms objects in two stages,

  • First, initialize the data
  • second, constructor execution (assignment).

Thus, if using the assignment method, the program execution is actually done twice, first initialization then assignment, while using member initialization only calls the string class constructor once. The more complex the class (more complex than the string class), the more expensive (inefficient) the process of creating objects through the assignment method.

A constructor with one argument also functions as an implicit conversion operator. For example, the following declarations of classes A and B,

class A { public:    A();
};  class B { public:    B(const A&);
};

In the program line excerpt below, there is an implicit conversion of object type A to B via the copy constructor of class B.

a
b=a;   // implicit conversion

3. explicit 

C++ provides a means, using the explicit keyword, to change the behavior of a one-argument constructor so that it does not function as a conversion operator. If class B declares an explicit copy constructor as follows,

class B { public:    explicit B(const A& a);   // explicit ctor
};

then implicit conversion of A to B cannot be done. Conversion of A to B can be done explicitly using typecast,

a;
b=static_cast<B>(a); atau
b=(B)a;

Implicit conversion can occur via function argument f with type B.

void f(const B& );

but f is accessed with a variable of type A, f(a). If class B blocks conversion implicitly then the function argument f becomes,

f((B)a); atau f(static_cast<B>(a));

Implicit object type conversions should be avoided because their effects may be greater on the overall application program and cannot be prevented at compile time, since constructing with a single argument is a valid and required program statement.

4. Copy Constructor and Copy Assignment 

So far, we have discussed the copy constructor as a class member that plays an important role when creating an object. If a class does not explicitly state the copy constructor of the class, the compiler adds a copy constructor in the form of a declaration,

C(const C& c);

Another form of copy constructor is as follows,

C(C& c); atau
C(C volatile& c); atau
C(C const volatile& c);

The C class copy constructor is a constructor that has one argument. A copy constructor may have more than one argument, as long as the argument has a default value.

C(C c);   // bukan copy constructor
C(C const& c,A a=b);   //copy constructor

A constructor with only C type arguments (without references) is not a copy constructor. A copy constructor is also needed when calling a function that accepts arguments in the form of objects of a class, 

void f(C x);

requires the copy constructor of class C to copy an object c of type C to an object x of the same type, namely when calling the function f(c)(pass-by-value).

Something similar happens when the function f is as follows,

C f()
{
   C c; ...
   return c;
}

send object c to another function that calls the function f().

The class C copy assignment operator is operator=, a function that has one argument of type C. Generally the copy assignment declaration has the form, 

C &operator=(const C &c);

Other possible forms are,

C &operator=(C &c); atau
C &operator=(C volatile &c); atau
C &operator=(C const volatile &c);

Copy assignments may have arguments of type C (not references), but cannot have more than one argument even if the argument has a default value (default argument). Like the copy constructor, the compiler will add a copy assignment if a class does not have this function. Copy assignments are needed to form objects through assignments, as in the following example;

class C { public:    C();   //ctor
   ~C();  //dtor
...
};

C c1;
C c2=c1;   //copy constructor C c3;
c3=c1;     //copy assignment

Class C does not have a copy constructor or copy assignment operator, so the creation of objects c2 and c3 uses the copy constructor and copy assignment added by the compiler to class C.

A class that has data with dynamic allocation (pointers) should not rely on copy constructors or copy assignment operators added by the compiler. Copy assignment is an additional result of the compiler that copies (memberwise copies) the pointer from one object (the copied object) to another object (the copied object), so that both objects refer to the same memory location. Problems arise if both objects have different lifetimes. If one of the objects has expired, the object's destructor returns the memory (dynamic memory) used by the object, even though the copy of the object still refers to the same memory location.

In the example of the copy assignment result b=a (shallow copy), it shows that both objects a and b refer to memory location p. If object a releases memory p (via destructor), then object b refers to a memory location that is no longer valid. Memory location p can be used by other objects if object a releases it. Likewise with memory location q, if object b has expired (out of scope, deleted, etc.) then the destructor of class B does not release memory q. As a result, there is a memory leak.

One way out is to explicitly state the copy constructor and copy assignment that a class requires so that the compiler does not create copy constructors and copy assignments to the class. Another alternative is to place the declaration of the copy constructor and copy assignment operator private as follows,

class C

{ ... private:    C(const C&);
   C &operator=(const C&);
};

The definition of copy constructor and copy assignment operator of class C in the example above is not necessary, because the purpose is to prevent the copying process using both functions. At the compilation stage, the use of assignment, b=a is still acceptable because the declaration of the assignment operator is available. At the time of linking, it will fail because the linker cannot find the definition of the copy assignment operator. This technique still has weaknesses, because other classes may still have access to the private copy constructor and copy assignment operator (through friendship relationships).

5. Destructor 

Destructor is a class member (member function) that functions to release memory when an object is no longer needed. The destructor function is the opposite of the constructor. Destructors do not have or require arguments. Destructors also do not return any value (do not have a return type). Like constructors, the compiler can add a destructor if a class does not have a destructor.

6. virtual Destructor 

A destructor can be a virtual function. This is a must if class B, 

  • is a base class.
  • Class D which uses B as a base class has members in the form of data with dynamic memory allocation (pointers).
class B { public:    B();
   ~B();
};

class D : public B
{ public:
   D() : p(new char[256]) {}
   ~D()    {
      delete[] p;
   } ... private:    char *p;
};

In the example, the destructor of base class B is not a virtual function. In C++, class D objects are generally used polymorphically by creating a class D (derived class) object and storing the address of the object in a class B (base class) pointer as in the following example,

void main(void)
{
   B *pB=new D();
   delete pB;
}

In the C++ standard, deleting a D (derived class) object through a B (base class) class pointer while the base class destructor is non-virtual has an uncertain effect (undefined behavior). If the C++ standard does not specify what should happen, then it is up to the compiler maker to determine the behavior of the program in this kind of condition. Generally, the compiler maker takes steps not to call the destructor of class D (derived class). Thus, when executing the delete command, the destructor of class D is not executed because the destructor of the base class B is non-virtual. As a result, the dynamic memory location used by class D is never released. This is another example of a memory leak by a program. The solution is to make the destructor of the base class B virtual,

class B { public: B(); virtual ~B();
...
}

Unlike destructors, there are no virtual constructors or virtual copy constructors. When creating an object, the type of the object must be known first, whether it is a class A, B, C object, etc. There is no aspect of the C++ language to realize virtual constructors directly, placing virtual in the constructor declaration is an error detected during the compilation process. The effect of a virtual constructor is not impossible to achieve, C++ allows creating virtual constructor idioms that rely on virtual functions in relation to the relationship between a class and its base class.

6. Summary 

So far the discussion of this article has not touched on the practical aspects of programming, however, in translating a design or understanding a program written by someone else, it is very important to know the basic rules according to the C++ standardization.

The points of discussion in this article include, 

  • The focus of the discussion is the aspect of object formation. It does not discuss the rules related to classes in C++ comprehensively.
  • Constructor is a class member that plays a role in creating objects. The compiler adds constructors when needed to classes that do not have constructors. Constructors do not have to have public access. Data initialization using constructors can be done by member initialization and assignment. Both do not have significant differences for ordinary data (built-in types such as char, int, float, etc.). The member initialization method is more efficient for data in the form of classes (user-defined types). 
  • A one-argument constructor can be used for implicit data type conversion. C++ provides an explicit way to change this behavior, because it relaxes C++'s promise as a strict type (type safe) language. 
  • A class needs a copy constructor and a copy assignment operator to duplicate an object of a class. This also happens when calling a function in a pass-by-value manner. If a class does not have a copy constructor and a copy assignment, the compiler adds them. The copy constructor and copy assignment added by the compiler work by memberwise copying and producing shallow copies for data with dynamic memory allocation. 
  • A destructor is a class member that functions when an object's lifetime expires. A base class's destructor should be virtual. 
  • Constructors are always non-virtual functions. The effects of virtual constructors and virtual copy constructors may be required in a design. The effects of virtual constructors can be realized through the polymorphism properties of a class. The effects of virtual copy constructors can be realized by utilizing the covariant return type aspect of a class hierarchy. Both of these require special discussion. 
  • The discussion of object creation has not been linked to the scope types in C++. C++ has a richer scope type compared to C, in addition to file scope, function scope, and block scope, C++ has class scope and namespace scope. One practical guide even suggests to delay (lazy initialization) object creation until it is not needed. 
  • Object creation may fail. This article does not discuss object creation failure, because that discussion is related to the discussion of exceptions in C++. The discussion of C++ exceptions (exception safety) is a separate topic.

Designing and implementing C++ classes is not easy, there are still many other aspects that have not been covered in this article. In the next article, we will discuss scope (visibility) in C++, C++ access specifiers, abstract classes, function overloading, class relationships, templates, etc.

Reference

  • Bjarne Stroustrup, "The C++ Programming Language", 3rd edition, AddisonWesley 1997 
  • Scott Meyers,"Effective C++", 2nd edition, Addison-Wesley 3. Scott Meyers,"More Effective C++", Addison-Wesley 
  • Q&A in C/C++ Users Journal. 
  • GOF,"Design Pattern", Addison-Wesley.

Harimurti W. freelance programmer living in Cimahi. Comments, corrections, criticisms, suggestions or questions regarding this article can be sent to the email address:  harmur@mailcity.com .

Biography

Harimurti Widyasena. Born in Jakarta on April 20, 1962. Graduated from high school in Jakarta in 1981, then continued his studies at the Bandung Institute of Technology majoring in Mechanical Engineering. Graduated with a bachelor's degree in 1989 then worked at PT. Nusantara Aircraft Industry.

Learned general computer knowledge since college and through work experience, starting from mainframes such as IBM 3031, then mini computers such as PDP 11/44, workstations (DEC Alpha) to the PC era in the late 80s with operating systems (eg: RSX-11, OSF/1, Windows, DOS) and different programming languages ​​(eg: FORTRAN, C++, VB). Experience so far is in making applications for analyzing flight test data, and several simulators including: power plant simulator (Steam Powerplant), maritime RADAR simulator, and ATC simulator. In 1997-1998 assisted (as a tutor) in a collaborative project between PT. IPTN-ITBUT (Thomson University) in improving human resources in the field of software engineering.

Currently interested in the field of software engineering in general, especially the analysis and design aspects of an application with OO techniques. In addition to the technical aspects in the engineering process (lifecycle) of a system/software product, the author's attention is paid to management aspects, including: software configuration management, software testing and forms of software engineering processes (eg: extreme programming).

Library:

By:

Source:

IlmuKomputer.Com

Example of C++ Class on Motor Dealer Receipt


C++ Class Implementation

Source Code:

#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#include <iomanip.h>

/*
*bundet.com
*Wawan Beneran
*Implementasi Class C++ pada Struk Dealer Motor
*/

class{
public:
char kd[5],*merk;
int hrg,jml,total;
}motor[30];

main()
{
char nmsales[20],nm[20],lagi;
float tb=0;
int i,j;
awal:
clrscr();
gotoxy(17,1);
cout<<"S&D MOTOR"<<endl;
cout<<"Jl. sunan wawan beneran No. 38 Telp. 021-192.168.8.1"<<endl;
cout<<"=============================================="<<endl;
cout<<" Nama Sales : ";cin>>nmsales;
cout<<" Nama Pembeli : ";cin>>nm;
cout<<" Jumlah data : ";cin>>j;
for(i=1;i<=j;i++)
{
cout<<" \n Data ke- "<<i<<endl;
cout<<" Kode [SPR/VRO/TGR] : ";cin>>motor[i].kd;
if(strcmp(motor[i].kd,"SPR")==0|| strcmp(motor[i].kd,"spr")==0)
{
motor[i].merk="Supra X";
motor[i].hrg=16540000;
}
else if(strcmp(motor[i].kd,"VRO")==0|| strcmp(motor[i].kd,"vro")==0)
{
motor[i].merk="Vario Techno";
motor[i].hrg=15790000;
}
else if(strcmp(motor[i].kd,"TGR")==0|| strcmp(motor[i].kd,"tgr")==0)
{
motor[i].merk="Tiger";
motor[i].hrg=24940000;
}
else
{
cout<<" Anda Salah Memasukkan Kode . . !!!, input Kode[SPR/VRO/TGR] . ."<<endl;
cout<<" Ingin Input Lagi : ";cin>>lagi;
if(lagi=='Y'||lagi=='y')
goto awal;
else
goto akhir;
}
cout<<" Masukan Jumlah Beli : ";cin>>motor[i].jml;
motor[i].total=motor[i].hrg*motor[i].jml;
tb=motor[i].total+tb;
}
clrscr();
gotoxy(23,1);
cout<<" S&D MOTOR"<<endl;
gotoxy(8,2);
cout<<"Jl. sunan wawan beneran No. 38 Telp. 021-192.168.8.1"<<endl;
gotoxy(8,3);
cout<<"======================================================"<<endl;
cout<<"Nama Sales :"<<nmsales<<endl;
cout<<"Nama Pembeli :"<<nm<<endl;
cout<<"======================================================"<<endl;
cout<<"No. Kode Merk Harga Jumlah Total "<<endl;
cout<<" Motor Motor Beli "<<endl;
cout<<"======================================================"<<endl;
for(i=1;i<=j;i++)
{
cout<<setiosflags(ios::left)<<setw(5)<<i;
cout<<setiosflags(ios::left)<<setw(6)<<motor[i].kd;
cout<<setiosflags(ios::left)<<setw(12)<<motor[i].merk;
cout<<setiosflags(ios::left)<<setw(14)<<motor[i].hrg;
cout<<setiosflags(ios::left)<<setw(10)<<motor[i].jml;
cout<<setiosflags(ios::left)<<setw(2)<<motor[i].total<<endl;
}
cout<<"======================================================="<<endl;
printf(" Total bayar Rp. %4.0f",tb);
cout<<endl;
cout<<"Mau Input data lagi[Y/T]:";cin>>lagi;
if (lagi=='Y'||lagi=='y')
goto awal;
else
goto akhir;
akhir:
getch();
}

Hope this is useful & happy learning!

Question 1

REZA MAHENDRA Jan 1, 2018, 07:24:00 Assalamualaikum. Excuse me, I want to ask, what is this function for?

printf(" Total bayar Rp. %4.0f",tb);

especially %4.0f? what is float?

REZA MAHENDRA REZA MAHENDRA Jan 2, 2018, 19:21:00 Thank you, sis.

Response 1

Hii REZA MAHENDRA that is the printf function using the precision parameter. You can read the complete documentation  HERE .

Hi REZA MAHENDRA, Yes


Post a Comment

Previous Next

نموذج الاتصال