2. คลาส Class

  • data members (attributes): ข้อมูลสมาชิกที่อยู่ในคลาส
  • member functions (methods): ฟังก์ชันสมาชิกที่อยู่ในคลาส
class Rect{
            public:
                int width,height;
                int getArea(){
                    return width*height;
                }
        };

        int main(){
            Rect myrect;
            myrect.width=2;
            myrect.height=3;
            cout<<"myrect.area() is "<<myrect.getArea();
            return 0;
        }

output

myrect.area() is 6

3.1. ตัวสร้าง Constructor

Constructor คือฟังก์ชันที่ถูกเรียกขณะทำการสร้าง instance (หรือ object) โดยชื่อฟังก์ชันจะต้องชื่อเดียวกับคลาสและไม่มีการ return

class Rect{
            public:
                int width,height;
                Rect(int w, int h){
                    width=w; height=h;
                }
                int getArea(){
                    return width*height;
                }
        };

        int main(){
            Rect myrect(2,3);
            cout<<"myrect.area() is "<<myrect.getArea();
            return 0;
        }

output

myrect.area() is 6

3.2. ตัวทำลาย Destructor

Deconstructor คือฟังก์ชันขณะที่ทำลายคลาสและคืนหน่วยความจำ(deallocation)

class Rect{
            public:
                int width,height;
                Rect(int w, int h){ width=w; height=h; }
                ~Rect(){ 
                    cout<<"Removing\n";
                }
                int getArea(){ return width*height; }
        };

        int main(){
            Rect myrect(2,3);
            cout<<"myrect.area() is "<<myrect.getArea()<<endl;
            return 0;
        }

output

myrect.area() is 6
Removing

3.3. ตัวเข้าถึงและตัวแก้ไข Accessors and Modifiers (Setter/Getter)

  • Accessors (หรือบ้างครั้งเรียกว่า Getter) ใช้เพื่ออ่านค่า Attributes จากภายนอกคลาส

  • Modifiers (หรือบ้างครั้งเรียกว่า Setter หรือ Mutator) ใช้เพื่อกำหนดค่าของ Attributes จากภายนอกคลาส

class Obj{
            public:
                float getMass(){
                    return mass;
                }
                void setMass(float m){
                    mass=m;
                }
            private:
                float mass;
        };
        int main(){
            Obj stone;
            stone.setMass(5);
            cout<<"Mass is "<<stone.getMass()<<endl; //cannot access getArea()
            return 0;
        }

output

Mass is 5

3.4 Static

static เขียนหน้าตัวแปรเมื่อต้องการ allocation เพียงครั้งเดียว ซึ่งจะให้ผลเฉพาะเมื่อใช้ใน function และ class

3.4.1 Static variable in function

เมื่อใช้เขียนหน้าตัวแปรใน function ตัวแปรนั้นจะจำค่าเดิมไว้สำหรับการเรียกใช้ครั้งหน้า

#include<iostream>
        using namespace std;
        int myFunc();
        int main(){
            cout<<myFunc()<<endl;
            cout<<myFunc()<<endl;
            cout<<myFunc()<<endl;
            cout<<myFunc()<<endl;
        }
        int myFunc(){
            static int x=0;
            return x++;
        }

output

0
1
2
3

3.4.2 static data member in class

เมื่อใช้เขียนหน้าตัวแปรในคลาส ตัวแปรนั้นจะแชร์ให้ทุก instances ที่เป็นคลาสประเภทเดียวกันเข้าถึงได้ สังเกตการกำหนดค่าเริ่มต้น int Obj::x=5; อยู่นอกคลาส

#include<iostream>
        using namespace std;
        class Obj{
          public:
            static int x;
            void setX(int _x){
                x=_x;
            }
            int getX();
        };
        int Obj::x=5;
        int main(){
            Obj myobj1;
            Obj myobj2;
            myobj1.setX(7);
            cout<<"myobj1.x: "<<myobj1.x<<endl;
            cout<<"myobj2.x: "<<myobj2.x<<endl;

            myobj1.setX(13);
            cout<<"myobj1.x: "<<myobj1.x<<endl;
            cout<<"myobj2.x: "<<myobj2.x<<endl;
            return 0;
        }
        int Obj::getX(){
            return x;
        }

output

Running /home/ubuntu/workspace/code32_static_class.cpp
myobj1.x: 7
myobj2.x: 7
myobj1.x: 13
myobj2.x: 13

3.5 Constant function

const หลังฟังก์ชันเพื่อไม่ให้แก้ไข data member ในคลาส

#include<iostream>
        using namespace std;

        class Obj{
          public:
            int x;
            mutable int y;
            //const int z=4; wont compile
            void setX(int _x) {
                x=_x;
            }
            void setY(int _y) const{
                y=_y;
                const int beta=8;
            }
        };
        int main(){
            Obj obj1;
            obj1.setX(5);
            obj1.setY(7);
            const int alpha=4;
            cout<<"x,y :"<<obj1.x<<","<<obj1.y<<endl;
            cout<<"alpha: "<<alpha<<endl;
            return 0;
        }

output

Running /home/ubuntu/workspace/code33_mutable.cpp
x,y :5,7
alpha: 4

4.1. Object with Function

เราสามารถสร้าง instance จาก class และคัดลอก instance ดังกล่าวเพื่อส่งให้ function ประมวลผลต่อได้ ตัวอย่างโปรแกรม

#include<iostream>
    using namespace std;
    class Obj{
      public:
        int x;
    };
    void showX_from_outside(Obj a){
        cout<<a.x;
    }
    int main(){
        Obj a;
        a.x=7;
        showX_from_outside(a);
    }

output

Running /home/ubuntu/workspace/code411_pass_obj_to_func.cpp                                               
7

4.2 friend

friend ใส่นำหน้าฟังก์ชัน เมื่อต้องการให้ฟังก์ชันนั้นเข้าถึง private data members หรือ private member functions ภายในคลาส

#include<iostream>
        #include <string>
        using namespace std;
        //no function prototype is required
        class Man{
            private:
                string hand;
                void isTouch (){ hand+="is touched"; }
                friend void hold(Man);
                friend void touch(Man);
            public:
                Man(){ hand="My hand "; }

        };
        void hold(Man jobs){
            jobs.hand+="is held";
            cout << jobs.hand << endl;
        }
        void touch(Man jobs){
            jobs.isTouch();
            cout << jobs.hand << endl;
        }
        int main(){
            Man jobs;
            hold(jobs);
            touch(jobs);
            return 0;
        }

output

Running /home/ubuntu/workspace/code34_friend.cpp
My hand is held
My hand is touched

5.1 Function Overloading

เราสามารถสร้าง function ที่มีชื่อซ้ำกันได้โดยมีอินพุตที่ต่างกัน

using namespace std;

        class printData 
        {
           public:
              void print(int i) {
                cout << "Printing int: " << i << endl;
              }

              void print(double  f) {
                cout << "Printing float: " << f << endl;
              }

              void print(char* c) {
                cout << "Printing character: " << c << endl;
              }
        };

        int main(){
            Vec2D A(3.0f, 4.0f),B(2.0f,1.0f),C,D;
            cout<< "A = "<<A;
            cout<< "B = "<<B;
            D=C=A*10.0f + B*0.5f;
            cout<< "C = "<< C;
            cout<< "D = "<< D;
            return 0;
        }

output

5
500.263
Hello C++

5.2 Operator Overloading

คลาสอาจมีตัวกระทำที่เราสามารถกำหนดเองได้ เช่นเรามีคลาสที่ชื่อ Complex ที่เก็บจำนวนจินตภาพ โดยอาจจะมีตัวกระทำ +, - และ อื่นๆ รูปแแบการเขียนโปรแกรม คือ

type classname::operator+(arg-list) { // operations }

ตัวอย่างการทำ operator overloading

#include <iostream>
        #include <math.h>
        using namespace std;
        class Vec2D{
        private:
            float x,y;
        public:    
            Vec2D(){ x = 0.0f; y = 0.0f;}
            Vec2D(float _x, float _y){
                x = _x;
                y = _y;
            }
            Vec2D operator - (Vec2D B){//subtraction
                Vec2D temp;
                temp.x = x - B.x;
                temp.y = y - B.y;
                return temp; 
            }
            Vec2D operator + (Vec2D B){//addition
                Vec2D temp;
                temp.x = x + B.x;
                temp.y = y + B.y;
                return temp; 
            }
            Vec2D operator = (Vec2D B){
                x = B.x;
                y = B.y;
                return *this;
            }
            Vec2D operator * (float k){
                Vec2D temp;
                temp.x = k * x;
                temp.y = k * y;
                return temp;
            }            
            friend ostream& operator<<(ostream& out, const Vec2D& A);
        };

        ostream& operator<<(ostream& out, const Vec2D& A) {
            return out << "( "<<A.x << ", "<< A.y << " )\n";
        }

        int main(){
            Vec2D A(3.0f, 4.0f),B(2.0f,1.0f),C;
            cout<< "A = "<<A;
            cout<< "B = "<<B;
            cout<< "A * 10 + B * 0.5 = "<< A*10.0f + B*0.5f;
            return 0;
        }

output

Running /home/ubuntu/workspace/code425_operator.cpp                                                       
A = ( 3, 4 )                                                                                              
B = ( 2, 1 )                                                                                              
C = ( 31, 40.5 )                                                                                          
D = ( 31, 40.5 )

6. I/O

input/output stream จาก fstream สามารถใช้เพื่อการเขียนอ่านไฟล์ โดยอาจใช้ตามตัวอย่างนี้

#include <iostream>
        #include <fstream>
        using namespace std;

        int main(){
            //write file
            ofstream myfile1 ( "myfile.txt" );
                myfile1<<"Hello World!"<<endl;
                myfile1<<"Class cs112 is awesome!!"<<endl;
            myfile1.close();

            //read file
            ifstream myfile2 ( "myfile.txt" );
            for (string line; getline(myfile2, line); ){
                cout << line << endl;
            }
            myfile2.close();
            return 0;
        }

output

Running /home/ubuntu/workspace/code426_read_write_files.cpp                                               
Hello World!                                                                                              
Class cs112 is awesome!!

7.1. Pointer of an object

An object or an instance created from a class can have a pointer as similar to other datatypes

7.1.1 declaration and initilization

In order to declare data tpye and initialize starting value. We can follow the pattern below. Please note that when we access a data member from pointer we use '->' not '.'.

#include<iostream>
            using namespace std;
            class Obj{
                public:
                int id;
                void inc(){++id;}
            };
            int main(){
                Obj a,b;
                Obj *pa,*pb;
                pa=&a;
                pb=&b;
                pa->id=5;
                b.id=7;
                cout<<"1 a.id="<<a.id<<", b.id="<<b.id<<endl;
                pb->inc();
                cout<<"2 a.id="<<a.id<<", b.id="<<b.id<<endl;
                return 0;
            }

output

Running /home/ubuntu/workspace/code71_class_pointer.cpp                                        
        1 a.id=5, b.id=7                                                                               
        2 a.id=5, b.id=8

7.2. & and *

operator and & work properly with object. In function input, '' means pasing by pointer and '&' means passing by reference.

#include<iostream>
        using namespace std;
        class Obj{
            public:
            int id;
        };
        void swap_id_reference(Obj &a, Obj &b){
            int temp=a.id;
            a.id=b.id;
            b.id=temp;
        }
        void swap_id_pointer(Obj *a, Obj *b){
            int temp=a->id;
            a->id=b->id;
            b->id=temp;
        }
        int main(){
            Obj a,b;
            a.id=0;
            b.id=1;
            cout<<"1 a.id="<<a.id<<", b.id="<<b.id<<endl;
            swap_id_reference(a,b);
            cout<<"2 a.id="<<a.id<<", b.id="<<b.id<<endl;
            swap_id_pointer(&a,&b);
            cout<<"3 a.id="<<a.id<<", b.id="<<b.id<<endl;
            return 0;
        }

output

        Running /home/ubuntu/workspace/code71_class_pointer_init.cpp                                        
        1 a.id=0, b.id=1                                                                               
        2 a.id=1, b.id=0                                                                               
        3 a.id=0, b.id=1

7.3. Return pointers from function

In many cases, return a copy of an object may not appropriate because it take time and memory to cpy the object. It is recommended to not copy the object from function to outer scope. The solution is to pass pointer back to the outer scope as the following code.

#include<iostream>
        using namespace std;
        class Obj{
            public:
            int id;
            Obj(int _id){id=_id;}
        };
        Obj* last_object(Obj* a, Obj* b){
            if(a->id < b->id){
                return b;
            }else{
                return a;
            }
        }
        int main(){
            Obj a(5),b(7);
            Obj* c=last_object(&a,&b);
            cout<<c->id;
        }

output

Running /home/ubuntu/workspace/code73_return_pointer.cpp
7

7.4. Pointer with const

the keyword 'const' makes the variable to be constant. However, location of the 'const' may have differnct meaning.

7.4.1 no constant

#include<iostream>
        using namespace std;
        void func( int *  p){
            int y;
            p=&y;
            *p=4;
        }
        int main(){
            int x;
            int *p=&x;
            x=5;//init
            func(p);
            cout<<x;
        }

output

        Running /home/ubuntu/workspace/code741_constant_arg.cpp                                        
        5

7.4.2 constant at the front (constant value)

#include<iostream>
        using namespace std;
        void func(const int *  p){
            int y;
            p=&y;
            *p=4;
        }
        int main(){
            int x;
            int *p=&x;
            x=5;//init
            func(p);
            cout<<x;
        }

output

        Running /home/ubuntu/workspace/code741_constant_arg.cpp                                        
        /home/ubuntu/workspace/code741_constant_arg.cpp: In function ‘void func(const int*)’:          
        /home/ubuntu/workspace/code741_constant_arg.cpp:6:7: error: assignment of read-only location ‘* p’                                                                                            
         *p=4;                                                                                     
           ^

7.4.3 constant at the back (constant address)

#include<iostream>
        using namespace std;
        void func( int * const p ){
            int y;
            p=&y;
            *p=4;
        }
        int main(){
            int x;
            int *p=&x;
            x=5;//init
            func(p);
            cout<<x;
        }

output

        Running /home/ubuntu/workspace/code741_constant_arg.cpp                                        
        /home/ubuntu/workspace/code741_constant_arg.cpp: In function ‘void func(int*)’:                
        /home/ubuntu/workspace/code741_constant_arg.cpp:5:6: error: assignment of read-only parameter ‘p’                                                                                             
             p=&y                                                                                     
              ^

9.1. การสืบทอด Inheritance

Inheritance คือการใช้ attributes และ method ของ Base class ซึ่งสามารถทำได้โดยเติมชื่อ Base class ไปหลังเครื่องหมาย ":" เช่น

class Derived: public Base{
    ...
};

โดยการกำหนดการเข้าถึงเป็น public จะทำให้การเข้าถึงใน base class ยังคงเหมือนเดิม

9.2. การเข้าถึง Access

  • public: ทุกคนเข้าถึงได้
  • private: เฉพาะ meber functions ในคลาสตัวเอง
  • protected: เฉพาะ meber functions ในคลาสตัวเองและคลาสที่สืบทอด
Access public protected private
Same class yes yes yes
Derived classes yes yes no
Outside classes yes no no
class Base { 
            private: 
                int MyPrivateInt=1; 
            protected: 
                int MyProtectedInt=2; 
            public: 
                int MyPublicInt=3; 
        }; 
        class Derived : public Base { 
            public: 
                int foo1() { return MyPrivateInt;} // Won't compile! 
                int foo2() { return MyProtectedInt;} // OK 
                int foo3() { return MyPublicInt;} // OK 
        }; 
        class Unrelated { 
        private: 
            Base B; 
        public: 
            int foo1() { return B.MyPrivateInt;} // Won't compile! 
            int foo2() { return B.MyProtectedInt;} // Won't compile 
            int foo3() { return B.MyPublicInt;} // OK 
        };

output

derived.foo2(): 2
derived.foo3(): 3
unrelated.foo3(): 3

9.3. private, public, and protected inheritance

class A{
            public:
                int x;
            protected:
                int y;
            private:
                int z;
        };

        class B : public A {
            // x is public
            // y is protected
            // z is not accessible from B
        };

        class C : protected A {
            // x is protected
            // y is protected
            // z is not accessible from C
        };
        // 'private' is default for classes
        class D : private A {
            // x is private
            // y is private
            // z is not accessible from D
        };

9.4. ตัวอย่างการเปลี่ยนการเข้าถึงด้วยการสืบทอด

ฟังก์ชัน getArea() ไม่สามารถเข้าถึงจาก main() เพราะการเข้าถึงถูกเปลี่ยนเป็น protectec ด้วยการสืบทอด

class Rect{
            public:
                int width,height;
                Rect(){}
                int getArea(){ return width*height; }
            protected:
                int key;
        };
        class Square: protected Rect{
            public:
                Square(int edge){
                    width=edge;
                    height=edge;
                    cout<<key<<endl; //ok
                    cout<<width<<endl; //ok
                }
        };
        int main(){
            Square mysq(5);
            //cout<<"mysq.area() is "<<mysq.getArea()<<endl; //cannot access getArea()
            return 0;
        }

9.4.1 private inheritance with scope (avoid using this confused pattern)

ถ้าไม่ใช้ scope "A::", B จะไม่สามารถเข้าถึง print() เพราะสืบทอดแบบ private เราไม่ควรใช้ pattern นี้ในการเขียนโปรแกรมเพราะอาจเกิดความสับสนเรื่องการเข้าถึง

#include<iostream>
        using namespace std;
        class A{
        public:
            void print(){cout<<"it's A"<<endl;}
        };
        class B:private A{
        public:
            void print(){
                cout<<"it's B"<<endl;
                A::print();
            }
        };
        class C: private B{
        public:
            void print(){
                cout<<"it's C"<<endl;
                B::print();
            }
        };
        int main(){
            C c;
            c.print();
            return 0;
        }

output

    Running /home/ubuntu/workspace/code941_private_inheritance.cpp
    it's C
    it's B
    it's A

9.4.2 protected inheritance

ถ้าต้องการป้องกันการเข้าถึงจากนอกคลาส protected inheritance จะเข้าใจได้ง่ายมากกว่า private inheritance

#include<iostream>
        using namespace std;
        class A{
        public:
            void print1(){cout<<"it's A"<<endl;}
        };
        class B:protected A{
        public:
            void print2(){
                cout<<"it's B"<<endl;
                print1();
            }
        };
        class C: public B{
        public:
            void print3(){
                cout<<"it's C"<<endl;
                print2();
            }
        };
        int main(){
            C c;
            c.print3();
            return 0;
        }

output

        Running /home/ubuntu/workspace/code941_private_inheritance.cpp      
        it's C 
        it's B  
        it's A

9.5. Order of constructing and destructing

ถ้ามีการสืบถอดหลายชั้น ลำดับการสร้างและการทำลายจะเป็นอย่างไร

#include<iostream>
    using namespace std;
    class A{
    public:
        A(){
            cout<<"Constructing A"<<endl;
        }
        ~A(){
            cout<<"Destructing A"<<endl;
        }
    };
    class B:private A{
    public:
        B(){
            cout<<"Constructing B"<<endl;
        }
        ~B(){
            cout<<"Destructing B"<<endl;
        }
    };
    class C: private B{
    public:
        C(){
            cout<<"Constructing C"<<endl;
        }
        ~C(){
            cout<<"Destructing C"<<endl;
        }
    };
    int main(){
        C c;
        return 0;
    }

output

Running /home/ubuntu/workspace/code950_sequenceConDeCon.cpp
Constructing A
Constructing B
Constructing C                                                                                         
Destructing C
Destructing B                                                                                          
Destructing A

9.5.1 order of constraction and deconstruction

สังเกตผลลัพธ์ในการสร้างและทำลาย a1 และ a2 โดยการสร้างเป็นไปตามลำดับซ้ายไปขวา ส่วนการทำลายจะเริ่มทำลายตัวที่ถูกสร้างหลังสุดก่อน

#include<iostream>
        using namespace std;
        class A{
        public:
            int id;
            A(int _id=0){
                id=_id;
                cout<<"Constructing A "<<id<<endl;
            }
            ~A(){cout<<"Destructing A "<<id<<endl;}
        };
        class B:public A{
        public:
            A a1,a2;
            B():a1(1),a2(2){cout<<"Constructing B"<<endl;}
            ~B(){cout<<"Destructing B"<<endl;}
        };
        class C:public B{
        public:
            C(){cout<<"Constructing C"<<endl;}
            ~C(){cout<<"Destructing C"<<endl;}
        };
        int main(){
            C c;
            return 0;
        }

output

Running /home/ubuntu/workspace/code950_sequenceConDeCon.cpp
Constructing A 0
Constructing A 1
Constructing A 2
Constructing B
Constructing C
Destructing C
Destructing B
Destructing A 2 
Destructing A 1
Destructing A 0

10.1. Separate compilation

In many cases the programmers want to secretly hide their codes from others. There are many ways to do this. One of the hidding techniques is separate compilation. For example, a programmer want to hide all codes in the class Obj, he can follow the example below.

First, he create two files. The header file

//Obj.h
        class Obj{
            public:
            int x;
            Obj(int);
            void inc(int);
        };

The cpp file

//Obj.cpp
        #include "Obj.h"
        Obj::Obj(int _x=0){
            x=_x;
        }
        void Obj::inc(int y){
            x+=y;
        }

The main file

//main.cpp
        #include "Obj.h"
        #include<iostream>
        using namespace std;
        int main(){
            Obj a(3);
            a.inc(2);
            cout<<a.x<<endl;
            return 0;
        }

Compilation

        g++ -c Obj.cpp
        g++ -c main.cpp
        g++ -o final main.o Obj.o
        ./final
        g++ -c Obj.cpp
        g++ -o final main.cpp Obj.o
        ./final

g++ options

          --help                   Display this information
          --version                Display compiler version information
          -time                    Time the execution of each subprocess
          -std=<standard>          Assume that the input sources are for <standard>
          --sysroot=<directory>    Use <directory> as the root directory for headers
                                   and libraries
          -B <directory>           Add <directory> to the compiler's search paths
          -v                       Display the programs invoked by the compiler
          -E                       Preprocess only; do not compile, assemble or link
          -S                       Compile only; do not assemble or link
          -c                       Compile and assemble, but do not link
          -o <file>                Place the output into <file>
          -Wa                      All option tells the compiler to show warnings 

        Options starting with -g, -f, -m, -O, -W, or --param are automatically
         passed on to the various sub-processes invoked by g++.  In order to pass
         other options on to these processes the -W<letter> options must be used.

        For bug reporting instructions, please see:
        <http://gcc.gnu.org/bugs.html>.

        C:\Users\Wasit>

10.2. multiple inheritance

#include<iostream>
        using namespace std;
        class Alpha{
        public:
          Alpha(){ cout<<"construct Alpha\n";}
          ~Alpha(){ cout<<"destroy Alpha\n";}
        };
        class Beta{
        public:
          Beta(){ cout<<"construct Beta\n";}
          ~Beta(){ cout<<"destroy Beta\n";}
        };
        class Chi: public Beta, public Alpha{ //private by default
        public:
          Chi(){ cout<<"construct Chi\n";}
          ~Chi(){ cout<<"destroy Chi\n";}
        };
        int main(){
            Chi c;
            return 0;
        }

output

        Running /home/ubuntu/workspace/code10_20_multi_inher.cpp
        construct Beta
        construct Alpha
        construct Chi
        destroy Chi
        destroy Alpha
        destroy Beta

10.3. multi-level inheritance

ย้อนกลับไปดู section 9

12.1 new and delete

#include<iostream>
    using namespace std;
    class Base{
        public:
        Base(int x, int y){cout<<x<<", "<<y<<"\n";}
        ~Base(){cout<<"Base destructs\n";}
    };
    int main(){
        Base *b=new Base[2]{{1,2},{3,4}};
        delete[] b;
        return 0;
    }

12.2 Shallow copy

copy address of a pointer

12.3 Deep copy

copy all data members

13.1. copy

see section 14.4

13.2. this

refer to current pointer of 

13.3. assignment operator overloading

see section 5.2

13.4. new and delete with an object in a class

don't forget to destruct the allocated memory to prevent memory leak

14.1. Polymorphism

There are three types of polymorphism

  • Overloading functions and operators
  • Inherritance
  • virtual function and abstract class

14.2. Virtual functions

virtual function ทำให้ polygon มีฟังก์ชัน area() ซึ่งจะกำหนดอีกครั้งหลังการสืบทอด

#include <iostream>
        using namespace std;

        class Polygon {
          protected:
            int width, height;
          public:
            void set_values (int a, int b)
              { width=a; height=b; }
            virtual int area ()
              { return 0; }
        };

        class Rectangle: public Polygon {
          public:
            int area ()
              { return width * height; }
        };

        class Triangle: public Polygon {
          public:
            int area ()
              { return (width * height / 2); }
        };

        int main () {
          Rectangle rect;
          Triangle trgl;
          Polygon poly;
          Polygon * ppoly1 = &rect;
          Polygon * ppoly2 = &trgl;
          Polygon * ppoly3 = &poly;
          ppoly1->set_values (4,5);
          ppoly2->set_values (4,5);
          ppoly3->set_values (4,5);
          cout << ppoly1->area() << '\n';
          cout << ppoly2->area() << '\n';
          cout << ppoly3->area() << '\n';
          return 0;
        }

output

20 10 0

Accessing the virtual function

        #include <iostream>
        class Base {
        public:
           virtual void f() {
               std::cout << "base\n";
           }
        };
        struct Derived : public Base {
            public:
            void f() override { // 'override' is optional
                std::cout << "derived\n";
            }
        };
        int main()
        {
            Base b;
            Derived d;

            // virtual function call through reference
            Base& br = b; // the type of br is Base&
            Base& dr = d; // the type of dr is Base& as  well
            br.f(); // prints "base"
            dr.f(); // prints "derived"

            // virtual function call through pointer
            Base* bp = &b // the type of bp is Base*
            Base* dp = &d // the type of dp is Base* as  well
            bp->f(); // prints "base"
            dp->f(); // prints "derived"

            // non-virtual function call
            br.Base::f(); // prints "base"
            dr.Base::f(); // prints "base"
        }

output


Virtual function as Oveririding

difinition from cambridge dictionary override verb (CONTROL) : to take control over something, especially in order to change the way it operates.

14.3. Abstract class

An abstract class is unable to construct an object. The "=0" indicates a null function. Therefore, the function member is incomplete requiring further implementaion.

#include <iostream>
        using namespace std;
        class Base{
            public:
            virtual void print()=0;
        };
        class Derived:public Base{
            public:
            void print(){
                cout<<"From Derived"<<endl;
            }
        };
        int main(){
            Base * pb= new Derived();
            //Base * pb2= new Base(); //cannot allocate an object of abstract type 'Base'
            pb->print();
            return 0;
        }

14.4. Virtual destructor

#include <iostream>
        using namespace std;
        class Base{

        public:
            Base(){cout<<"Base Constructor Called\n";}
            virtual ~Base(){cout<<"Base Destructor called\n";}

        };
        class Derived:public Base{

        public:
            Derived(){cout<<"Derived constructor called\n";}
            ~Derived(){cout<<"Derived destructor called\n";}

        };
        int main(){

            base* b = new Derived;
            delete b;

        }

Copy constructor

#include <iostream>
        using namespace std;
        class Base{
            public:
                int *ptr;
                Base(){
                    ptr=new int(1);
                }
                Base(const Base &b){//copy constructor overloading
                    ptr=new int(*(b.ptr));
                }
                ~Base(){
                    delete ptr;
                }
        };
        int main(){
            Base B1, B2=B1;
            cout<<B1.ptr<<" value:"<<*(B1.ptr)<<endl;
            cout<<B2.ptr<<" value:"<<*(B2.ptr)<<endl;
            while (1){
                Base B3;
            }
            return 0;
        }

Copy constructor of derived class

#include <iostream>
    using namespace std;
    class Base{
        public:
            Base(){
                cout<<"base construct\n";
            }
            virtual ~Base(){
                cout<<"base destruct\n";
            }
    };
    class Derived: public Base{
    public:
        int *ptr;
        Derived(){
            ptr=new int(1);
            cout<<"derived construct\n";
        }
        Derived(const Derived &d){//copy constructor overloading
                ptr=new int(*(d.ptr));
                cout<<"derived copy construct "<<ptr<<endl;
            }
        ~Derived(){
            cout<<"derived destruct "<<ptr<<endl;
            delete ptr;

        }
    };
    int main(){
        Derived D1;
        while (1){
            Base *D2 = new Derived(D1);
            delete D2;
        }
        return 0;
    }

Problem delete array of derived class

#include<iostream>
        using namespace std;
        class Base{
            public:
            Base(){cout<<"Base constructs\n";}
            virtual ~Base(){cout<<"Base destructs\n";}
        };
        class Derived: public Base{
            public:
            int *pt;
            Derived(){
                pt=new int[100];
                cout<<"Derived constructs\n";
            }
            ~Derived(){
                delete[] pt;
                cout<<"Derived destructs\n";
            }
        };
        int main(){
            while(1){
                //Base b = Base(); //works
                //Derived d= Derived();
                Base *b = new Derived[3];
                delete[] (Derived*)b;//if there is no 'virtual', delete only base object
            }
            return 0;
        }

Template [extra]

Tempalte allow us to create functions and containers for an unspecified datatype. Example: to crate a singly linked list that able to push and pop a particualr datatype.

Input argument to executable file[extra]

#include <iostream>
    using namespace std;
    int main(int argc, char** argv) {
        for(int i=0; i<argc;i++){
            cout<<argv[i]<<endl;
        }
        return 0;
    }

output

    >>main.exe -l -a
    main.exe
    -l
    -a