C++ User Defined Data Types

Discussion in 'C++' started by BiplabKamal, May 26, 2016.

  1. We learned that all the variables have type. We also learned that type specify the memory size required to store the variable data and the interpretation of the data. So far we discussed about predefined (in-built) data types which are specified in the language specification. We use language keywords for using those types. In C++ language pre-defined data types and operations are rich but they are low level. These fundamental data types also reflect the capability of conventional computer hardware but they are not enough to build advanced programs. So C++ allows the programmers to define new types using keywords ‘class’, ‘struct’, ‘union’ and ‘enum’. These key words define new complex data types which are based on in-built data types. This gives the programmer the enormous power to define simple to very complex data types with operations. Class data type was not part of original C language but added in C++ to support object oriented programming. C++ also enhanced the C struct type so it works almost similar to class type. The main characteristic of object oriented programming is hiding data and expose functions which operates on the underlying data. C++ struct and class are packages of data and functions. Functions operate on the attached data of the package it belongs to. In this chapter we will get familiar with the keywords used to define new data types. We will know the basic overview of class, structure, enumeration and union data types.

    Creating data type using keyword ‘struct’ and ‘class’



    Origination of struct data type was in C which was basically grouping related data. For example, the name, age, address and gender of person is related to single person. And we have to manipulate those information for many persons. Here we need to create a data pack which store all the information about a person. Here is the new type we can create with following syntax:
    Code:
    struct <new type name>
    {
        <member decleration>;
        ...
    };
    
    For example if we want to create a new type Person it will look like:
    Code:
    struct Person
    {
        wchar_t Name[100];
        wchar_t Address[1000];
        float Age;
        wchar_t Gender;
    };
    
    In the above definition ‘Person’ is a new type and ‘Name’, ‘Address’,’Age’ and ‘Gender’ are the members of the new type Person. We can create any number of variables of type Person like:
    Code:
    Person p1; // Without initialization
    Person p2{ L"John",L"Niladri Nagar, Electronic City Phase 1, Bangalore -560100",39.5,'M' };//With initialization
    
    We can use ‘class’ in place of ‘struct’ because both are similar with few difference:
    Code:
    class Person
    {
    public:
        wchar_t Name[100];
        wchar_t Address[1000];
        float Age;
        wchar_t Gender;
    };
    
    See the similarity and difference between structure and class version. For class you need to have public key word to make it similar to struct version. class/struct members can be public or private. Public members can be accessed from outside of the class/struct but private members can be only accessed within the struct/class. For class members default access is private whereas for struct the default is public. We will use class for both class and struct for future discussion.

    class keyword defines a new data type which contains elements called class members. Class member are of two types: member variables and member functions. Member variables are variables of inbuilt or other user defined data types and member functions are functions that operates within the scope of the class. Declaring a variable of class type is called instantiation and the variable is called instance or object of the class. Class members are declared inside curly braces ({}) after the class name. Each class member can have access specifier of public or private. Private means the member is not accessed from outside the class. If you do not specify the access specifier by default the member is private (public for struct). Class member functions can be defined inside the class or outside the class. Member also can have static type which make it independent of instance whereas the non-static member’s scope is within an instance. Static members can be used without creating any instance but non-static members cannot be used without instance. Normally member variables are made private and members functions are made public. Non-static member variables hold the state of an object and the public member functions exhibit the behavior of the object. Static member function can access only static members but non-static member function can access both static and non-static members. Non-static public members are used with a dot(.) operator of an object and static public members are used with class scope resolution operator :):) with the class name. Following example will show the usage of class:

    Code:
    class MyClass
    {
    private: // Following members are private
        int member1;// Non-static member variable
        static int instancecount;// Static member variable
    public://Following members are public
        static void IncrementInstanceCount();//Static member function
        static int GetInstanceCount();//Static member function
        void SetMember1(int);//Non-static member function
        int GetMember1();//Non-static member function
    };
    // Definition and initialization of static member variable 
    int MyClass::instancecount{ 0 };
    //Definition of Member functions out side the class
    void MyClass::SetMember1(int val)
    {
        member1 = val;
    }
    int MyClass::GetMember1()
    {
        return member1;
    }
    void MyClass::IncrementInstanceCount()
    {
        ++instancecount;
    }
    int MyClass::GetInstanceCount()
    {
        return instancecount;
    }
    int main()
    {
        MyClass obj1; //Creating the instance
        MyClass::IncrementInstanceCount(); // Calling static members function
        obj1.SetMember1(10); // Callig non-static member function
    
        // Creating another instance
        MyClass obj2;
        MyClass::IncrementInstanceCount();
        obj2.SetMember1(20);
        // Creating another instance
        MyClass obj3;
        MyClass::IncrementInstanceCount();
        obj3.SetMember1(30);
    
        // Getting the total number of instance created which will be 3
        int totalinstance = MyClass::GetInstanceCount();
        // Adding the member value of all instances which should be 60
        int totalvalue = obj1.GetMember1() + obj2.GetMember1() + obj3.GetMember1();
        
    }
    
    You can replace the ‘class’ keyword with ‘struct’ keyword. The definition of static member variable has to be outside the class. Member function can be defined inside the class also like:
    Code:
    class MyClass
    {
    private: // Following members are private
        int member1;// Non-static member variable
        static int instancecount;// Static member variable
    public://Following members are public
        static void IncrementInstanceCount()//Static member function
        {
            ++instancecount;
        }
        static int GetInstanceCount()//Static member function
        {
            return instancecount;
        }
        void SetMember1(int val)//Non-static member function
        {
            member1 = val;
        }
        int GetMember1()//Non-static member function
        {
            return member1;
        }
    };
    // Definition and initialization of static member variable 
    int MyClass::instancecount{ 0 };
    
    A class resembles the real world objects. A real world object has it’s parts, property and behavior. In a class the public member variables maps to the property, private member variables maps to it’s parts and the public member functions mapped to the behavior. For example a car has a body, wheels, engine, color, max speed etc. Here body, engine and wheels are parts of the car, color and max speed is the property and action like run, accelerate, stop etc. are behaviors. So a Car class will have private members for body, wheels and engine. It will have color and max speed as public members and run, stop, accelerate as public functions. Following code will show how a class to represent the car family looks like:
    Code:
    class CarEngine
    {
        
    };
    class CarBody
    {
    
    };
    enum class CarColor:char{red, blue,white};
    class CarWheel
    {
    
    };
    class Car
    {
        CarEngine engine;
        CarBody body;
        CarWheel wheel[4];
        void StopEngine()
        {
            //Stop engine
        }
        void StartEngine()
        {
            //Start engine
        }
        void ApplyBreak()
        {
            //Apply break
        }
    public:
        CarColor color;
        unsigned short maxspeed;
        void Run()
        {
            StartEngine();
            Accelerate(10);
        }
        void Stop()
        {
            ApplyBreak();
            StopEngine();
        }
        void Accelerate(unsigned short acc)
        {
            // Increase Ingine throttle
            // Change gear if required
        }
        
    };
    int main()
    {
        Car c;
        c.Run();
        c.Accelerate(40);
        c.Stop();
    }
    
    
    In the above code a class is using another class as the type of it’s member variables. The main purpose of a class is to hide the parts or data from the outside world and expose the behaviors which are needed by the external world.

    Creating Enumeration data type using keyword ‘enum’



    Enumeration type is probably the simplest user defined data type. Enumeration helps to create a data type whose value can be one from a set of values called enumerators. Each enumerator is a constant integral value. So once they are set, cannot be changed. For example
    Code:
        enum class Color { RED, BLUE, GREEN }; // Creating the new type Color
        Color c = Color::RED; // Creating a variable of type Color
        c = 0;// Error: it can not have arbitrary value 
    
    Here RED, BLUE and GREEN are created as constant values with 0, 1 and 2

    The underlying type of an enumeration type is integer by default but you can also control the type and size of the enumeration variables by specifying the underlying type different. The type is specified with a colon:)) after the enumeration identifier. The size of following enumeration type will be equal to the size of short.

    enum class ElementaryColor:short { RED, BLUE, GREEN };

    The above enumeration is called scoped enumeration and the constants RED, BLUE and GREEN are scoped enumerator. The are only visible within the enumeration class. If you remove the ‘class’ keyword it becomes non-scoped enumeration. Non-scoped enumerators are like constants and visible in the environment where the enumeration is defined . For example, following enumerators will conflict as redefinition of RED, BLUE and GREEN.
    Code:
        enum  ElementaryColor { RED, BLUE, GREEN };
        enum  TraficSignal { RED, BLUE, GREEN };
    
    But following code will not give error:
    Code:
        enum  class ElementaryColor { RED, BLUE, GREEN };
        ElementaryColor c = ElementaryColor::RED;
        
        enum  class TraficSignal { RED, BLUE, GREEN };
        TraficSignal s = TraficSignal::RED;
    
    Each enumerator is attached to a value of its underlying type. If not initialized then the value of an enumerator will be the value of the previous enumerator plus one. Firs enumerator will be 0 if not initialized. In the above examples the underlying value of RED =0, BLUE =1 and GREEN=2. You can change the value sequence by initializing them. If you declare the enumeration class like:

    enum class ElementaryColor { RED, BLUE=5, GREEN };

    Then values will be RED =0, BLUE =5 and GREEN=6.

    The name of an un-scoped enumeration is not compulsory. If you omit the name then the declaration only introduces the enumerators into the enclosing scope. You cannot use unnamed enumerator as a type but as constant values. For example :

    enum {X0, X1, Y0 = 0, Z = X0 + 2 } v; // defines constants X0 = 0, X1 = 1, Y0 = 0, Z = 2

    When an un-scoped enumeration is a class member, its enumerators may be accessed using class member access operators*.*and*->:
    Code:
    class EnumStruct
    {
    public:
        enum Color:char { RED = 'r', GREEN = 'g', BLUE ='b' };
    };
    EnumStruct x;
    EnumStruct* p = &x;
    
    char c1 = EnumStruct::Color::BLUE;// allowed only in C++11 and later
    char c2= EnumStruct::BLUE;
    char c3 = x.BLUE;
    char c4 = p->BLUE;
    
    It is advisable to use scoped enum always because it is more type safe and does not conflict with other enum or variable names.

    Creating data type using keyword ‘union’



    The main characteristic of union is that it create a data type which encapsulates different types of data but represent as one data type at a time. You can think it as a box where you can keep different but predefined kind of objects. You can keep only one object at a time. So the size of the box is fixed but the size of the object inside the box can be different. The size of the box should be big enough to contain the object with largest size. In C++ union, a single storage is used to store different types of data. The syntax is :

    union <identifier>{<Member decleration>};

    Here is an example:
    Code:
    union MyUnion
    {
        int intdata;
        short shortdata;
        char chardata;
        float floatdata;
    };
    
    The MyUnion type creates a variable of size equal to the size of largest data member which 4. Now you can use the variable for any of it’s member at a time. Following main function will show the implication-
    Code:
    int main()
    {
        MyUnion u;
        u.floatdata = 100; // float value is assigned so it should be used as float only
        float f = u.floatdata; // valid value
        char c = u.chardata; //invalid data
        int i = u.intdata; // invalid data
        short s = u.shortdata;// invalid data
        
        MyUnion u2{0};// initializing to set all bits to zero
        u2.shortdata = 100;//short integer value is assigned so it should be used as short
        float f2 = u2.floatdata; // invalid value
        char c2 = u2.chardata; //possibility of data loss
        int i2 = u2.intdata; // possibility of data loss
        short s2 = u2.shortdata;// valid data
    }
    
    It is like structure but all the members usage the same memory address. So you can use it only for a single member at a time. Language does not keep track which member has valid value. That needs to be handled by the programmer. Most of the time union is not used as a stand alone variable but part of another class or structure. Following example resembles this:
    Code:
    #include<iostream>
    union MyUnion
    {
        int intdata;
        short shortdata;
        char chardata;
        float floatdata;
    };
    enum class Type {Integer, Short, Float,Char};
    struct Item
    {
        Type type;
        MyUnion item;
    
    };
    void ShowData(Item items[],int size)
    {
        for (int i{ 0 };i < 5;++i)
        {
            std::cout << "Item = ";
            switch (items[i].type) {
            case Type::Char:
                std::cout << items[i].item.chardata;
                break;
            case Type::Float:
                std::cout << items[i].item.floatdata;
                break;
            case Type::Integer:
                std::cout << items[i].item.intdata;
                break;
            case Type::Short:
                std::cout << items[i].item.shortdata;
                break;
            default:
                break;
            }
            std::cout << std::endl;
        }
    }
    
    int main()
    {
        Item items[5];
        Item item;
        item.type = Type::Integer;
        item.item.intdata = 100;
        items[0] = item;
    
        item.type = Type::Short;
        item.item.shortdata = 10;
        items[1] = item;
    
        item.type = Type::Char;
        item.item.chardata = 'r';
        items[2] = item;
    
        item.type = Type::Float;
        item.item.floatdata = 100.50;
        items[3] = item;
    
        item.type = Type::Char;
        item.item.chardata = 'q';
        items[4] = item; 
        ShowData(items, 5);
    }
    
    class, struct, enum and union all looks similar but purpose different. struct is historically used for grouping data and contains only public data members. For example a structure can represent a record of a database table. Each data member of the structure will represent a field of a record. On the other hand class type represent as an active object which is self managed. For example the whole database can be represented by a class which have tables, and queries. Client of a class object manipulate database and generate report using public member functions. Union is used where variant data type is involved. Enumerations types are used select options among a list of choices.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice