C++学习Day0——了解C++中的名词和概念1

初识C++,所以看了下谭浩强老师的《C++程序设计》,第一次看,先了解一下C++中比较突出的概念。以下笔记是摘录自第8,9,11,12章节。先了解基本概念,明白以下C++语言和面向对象的思想,具体的细节问题以后具体分析。

目录

 

基于对象的程序设计

   类和对象的特性

一,对象

二,类的声明和对象的定义

三,类的成员函数

四,对象成员的引用

五,类的封装性和信息隐蔽

    怎样使用类和对象

一,利用构造函数对类对象进行初始化

二,析构函数    

三,调用构造函数和析构函数的顺序

四,对象数组

五,对象指针

六,公用数据的保护

七,对象的动态建立和释放    

八,对象的赋值和复制

九,静态成员

十,友元

十一,模板类

面向对象的程序设计

    继承和派生

一,继承和派生的概念

二,派生类的声明方式

三,派生类的成员

四,派生类成员的访问属性

五,派生类的构造函数和析构函数

六,多重继承

七,基类与派生类的转换

八,继承和组合

*九,继承在软件开发中的重要意义

    多态性和虚函数

一,多态性的概念

二,例子

三,利用虚函数实现动态多态性

四,纯虚函数与抽象类


 

基于对象的程序设计

   类和对象的特性

一,对象


    1,类
        1,概念
        2,封装与信息隐蔽
        3,抽象
        4,继承和重用
        5,多态
    2,面向对象程序设计的特点
        1,面向过程中,所有数据都是公用的。
        2,面向对象中,数据与外界分隔。
            把数据和操作封装成一个对象。
            程序设计者的任务:1,设计所需的各种类和对象。
                                            2,考虑怎样向有关对象发送信息,以完成所需的任务。
    3,类和对象的作用
        一组数据是与一组操作相对应的。因此人们把相关的数据和操作放在一起,形成一个整体,与外界相对分隔。这就是面向对象的程序设计中的对象。
        
        面向过程:    程序 = 算法 + 数据结构
        面向对象:    对象 = 算法 + 数据结构
                    程序 = (对象 + 对象 + ……)+ 消息
            或    程序 = 对象s + 消息
    
    4,面向对象的软件开发
        1,面向对象分析
        2,面向对象设计
        3,面向对象编程
        4,面向对象测试
        5,面向对象维护

二,类的声明和对象的定义


    1,类和对象的关系
    
    2,声明类类型
    
    3,定义对象的方法
        1,先声明类类型,然后再定义对象
        2,在声明类的同时定义对象
        3,不出现类名,直接定义对象(不用)
    
    4,类和结构体的异同
        1,C++使struct 具有类的特点,用struct声明的结构体类型实际上就是类。
        
        2,用struct声明的类,如果对其成员不作private或public的声明,系统默认是public。
            用class定义的类,如果不作private或public的声明,系统默认是private。

三,类的成员函数


    
    1,成员函数的性质
        成员函数可以访问本类对象中任何成员(包括公有的和私有的),可以引用在本作用域中有效的数据。
    2,在类外定义成员函数
        "::"是作用域限定符,也叫作用于运算符。
        如果不带"::"则说明该函数不属于任何类。是全局函数。
        类函数必须先在类体中作原型声明,然后在类外定义。也就是说类体的位置应在函数定义之前,否则编译会出错。
    
    3,内置成员函数
        inline在类中具体的用法
    4,成员函数的存储方式
        一个对象所占的空间大小只取决于该对象中数据成员所占的空间,而与成员函数无关。函数的目标代码是存储在对象空间之外的。
        如果定义了10个对象,这些对象的成员函数对应的是同一个函数代码段,而不是10个不同的函数代码段。
        
        this指针 初识。


        
四,对象成员的引用


    1,通过对象名和成员运算符访问对象中的成员
            对象名.成员名
            
    2,通过指向对象的指针访问对象中的成员
            Time t, *p; p = &t; cout << p->hour;
            
    3,通过对象的引用访问对象中的成员
            如果为一个对象定义了一个引用,实际上他们是同一个对象,只是用不同的名字表示而已。

 

五,类的封装性和信息隐蔽


    1,公有接口和私有实现的分离
        当接口与实现分离时,只要类的接口没有改变,对私有实现的修改不会引起程序的其他部分的修改。
        主要功能是使程序的设计、修改和调试简单。
    
    2,类声明和成员函数定义的分离
        类声明头文件是用户使用类库的接口
        包含成员函数定义的文件就是类的实现。
        类的声明和函数定义是分别放在两个文件中。
    
    3,面向对象程序设计中的几个名词
        1,方法: 类的成员函数在面向对象程序理论中被称为“方法”。
        
        
        


    怎样使用类和对象

 

一,利用构造函数对类对象进行初始化


    1,对象的初始化
        类是一种抽象类型,并不占内存空间,所以无处容纳数据。
        对象代表一个实体,每一个对象都有它确定的属性。
        每一个对象都应当在它建立之时就有确定的内容,否则就是去了对象的意义。
    
    2,用构造函数实现数据成员的初始化
        构造函数:    是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。
                    是在声明类的时候由类的设计者定义的。
                    1,构造函数的名字必须与类名同名,而不能任意命名。
                    2,它不具有任何类型,不具有返回值。
                    3,构造函数不需用户调用,也不能被用户调用。
                    4,可以用一个类对象初始化另一个类对象
                    5,在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句,例如cout。
                        但是一般不提倡在构造函数中加入与初始化无关的内容,以保持程序的清晰。
                    6,如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数,只是这个构造函数的函数体时空的,没有参数,也不执行初始化操作。
                    
        方式:           
                    1)在类内定义构造函数
                    2)在类内对构造函数进行声明而在类外定义构造函数
    
    3,带参数的构造函数
        构造函数名(类型1 形参1,类型2 形参2 ……)
        定义对象的形式: 类名 对象名(实参1, 实参2, ……)
        
    4,用参数初始化表对数据成员初始化
        这种方法不在函数体内对数据成员初始化,而是在函数首部实现。
        类名 :: 构造函数名([参数表])[:成员初始化表]
        {
            [构造函数体]
        }

        //其中方括号内为可选项。
        说明:如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不是在参数初始化表中对其初始化。
        

class Student
        {
            public :
                Student(int n, char char s, nam[]):num(n), sex(s)
                {
                    strcpy(name, nam);
                }
            private:
                int num;
                char sex;
                char name[20];
        };
        
        Student stud1(10101, 'm', "wang_li");


    
    5,构造函数的重载
        概念:在一个类中可以定义多个构造函数,以便为对象提供不同的初始化的方法,供用户选择。
        这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。
        例子:
        

#include <iostream>
        using namespace std;
        class Box
        {
            public :
            Box();                    //声明一个无参的构造函数
            Box(int h, int w, int len) : height(h), width(h), length(len)
            {}                        //定义一个有参的构造函数,用参数的初始化表对构造成员初始化

            int colume();
            
            private:
                int length;
                int width;
                int length;
        };
        
        Box::Box()                    //类外定义无参构造函数Box
        {
            height = 10;
            width = 10;
            length = 10;
        }
        
        int Box :: volume()            //类外定义声明成员函数volume
        {
            return (height * width * length);
        }


        如上,在建立对象时可以给出无参和两个参数,系统会分别调用相应的构造函数。
        
        
        
        
    6,使用默认参数的构造函数

        构造函数中的参数的值既可以通过实参传递,也可以指定为某些默认值,即如果用户不指定实参值,编译系统就使形参取默认值。
        1)应该在什么地方指定构造函数的默认参数?
            应该在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。
        2)声明构造函数时,形参名可以省略
            Box(int = 10, int = 10, int = 10);
        3)如果构造函数的全部参数都指定了默认值,则在定义对象时可以给一个或几个实参,也可以不给出实参。由于不需要实参也可以调用构造函数,因此全部参数都指定了默认值的构造函数也属于默认构造函数。
        一个类只能有一个默认构造函数,也就是说,可以不用参数而调用的构造函数,一个类只能有一个。
        4)在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
        一般不应同时使用构造函数的重载和有默认参数的构造函数。


        
        
二,析构函数

    析构函数是一个特殊的成员函数,它的作用与构造函数相反。析构函数是与构造函数作用相反的函数。
    
    当对象的生命周期结束时,会自动执行析构函数,具体以下4种情况,程序会执行析构函数:
    1)如果在一个函数中定义了一个对象,当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
    2)静态局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
    3)如果定义了一个全局的对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数)时,调用该全局的对象的析构函数。
    4)如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。
    
    析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。
    
    一个类可以有多个构造函数,但只能有一个析构函数,它没有函数参数,也不能被重载。
    


三,调用构造函数和析构函数的顺序

    1,同一类存储类别的对象而言:
        先进后出
        先构造的后析构,后构造的先析构。
    2,系统在什么时候调用构造函数和析构函数:
        1)如果在全局范围中定义对象(即在所有函数之外定义的对象),那么他的构造函数在本文件模块中的所有函数执行之前调用。
        
        2)如果定义的时局部自动对象(例如在函数中定义对象),则在建立对象时调用其构造函数。如果对象所在的函数被多次调用,则每次建立对象时都要调用构造函数。在函数调用结束、对象释放时先调用析构函数。
        3)如果在函数中定义静态局部对象,则只在程序第一次调用此函数定义对象时调用构造函数一次,在调用函数结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
        
        注意:主要考虑的时对象的存储类别和生命周期。


四,对象数组

    1,定义一个类的对象数组。
    2,初始化,调用构造函数。
        单个参数的初始化。
        多个参数的初始化,编译系统只为每个对象元素的构造函数传递一个实参,所以在定义数组时提供的实参个数不能超过数组元素个数。
        实现方法是在花括号中分别写出构造函数名并在括号内指定实参。

 

五,对象指针

    1,指向对象的指针
            类名 * 对象指针名;
            
    2,指向对象成员的指针
        1)指向对象数据成员的指针
            数据类型名 * 指针变量名
        2)指向对象成员函数的指针
            #1普通的函数指针:              
            类型名(* 指针变量名)(参数列表);
            void (*p)();   
            p = fun;     
            (*p)();
            
            #2类的公有成员函数的指针变量:    
            数据类型名 (类名 :: *指针变量名) (参数列表);
            指向一个公有成员函数的一般形式:
            指针变量名 = &类名 ::成员函数名;
            void (Time :: *p2)();             //*的优先级高于()
            p2 = &Time::get_time;            
            
    3,this指针
        作用:就是区分同类不同对象中成员的调用,如何去找对应的对象。
        
        在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,成为this。
        它是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的其实地址。
        
        this指针是隐式使用的,它是作为参数被传递给成员函数的。
        
        这是编译系统自动实现的。

六,公用数据的保护

    既要使数据能在一定范围内共享,又要保证它不被任意修改,这时可以把有关的数据定义为常量。
    
    1,常对象
        定义对象时加上const,指定对象为常对象。常对象必须要有初值。
        Time const t1(12, 34, 56);
        凡保证数据成员不被改变的对象,可以声明为常对象。
        类名 const 对象名[(实参表)];
        const 类名 对象名[(实参表)];
        两者等价。   初始化后不可改变。
        
        说明:如果一个对象被声明为常对象,则通过该对象只能调用它的常成员函数,而不能调用该对象的普通成员函数(除了由系统自动调用的隐式的构造函数和析构函数),常成员函数时常对象的唯一的对外接口。
        1)那么怎样才能引用常对象中的数据成员呢?将该成员函数声明为const即可:
            void get_time() const;   //常成员函数
        2)常成员函数可以访问,但是不允许修改常对象中的数据成员的值。
        以上保证了常对象中的数据成员的值绝对不会改变。
        
        一定要修改常对象中的某个数据成员的值  可以用关键字  mutable
        如: mutable int count;
        
    2,常对象成员
        1)常数据成员
            注意:只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常数据成员赋值。
            构造函数只能用参数初始化表对常数据成员进行初始化。
            Time :: Time(int h) : hour(h) {}  //合法
            Time :: Time(int h) {hour = h;}   //非法
            
        2)常成员函数
            声明常成员函数的一般形式:
                类型名    函数名    (参数表) const  //const 是函数类型的一部分
                
    3,指向对象的常指针
        将指针变量声明为const型,这样指针变量始终保持为初值,不能改变,即其指向不变。
        定义指向常对象的常指针变量的一般形式:
            类名 * const 指针变量名;
            Time *const ptr1 = &tl1;
            
        往往用常指针作为函数的形参,目的是不允许在函数执行过程中噶便指针变量的值,使其始终指向原来的对象。
        
    4,指向常对象的指针变量
        定义指向常变量的指针变量的一般形式为:
            const char *ptr;
        定义指向常对象的指针变量的一般形式为:
            const Time *p;
    
    5,对象的常引用
    
    6,const型数据的小结
    


七,对象的动态建立和释放

        new  , delete
        需要定义一个执行本类的对象的指针变量来存放该地址。
        Box *pt;
        pt = new Box;
        
        Box *pt = new Box(12, 15, 18);
        
        delete pt;
    


八,对象的赋值和复制

    1,对象的赋值
        对象名1 = 对象名2;
        stu2 =  stu1;
        1)对象的赋值只对其中数据成员赋值,而部队成员函数赋值。
        2)类的数据成员中不能包括动态分配的数据,否则在赋值时可能出现严重后果。
    
    2,对象的复制
        Box box2(box1);     //用已有的对象box1去克隆出一个新对象box2
        Box box2 = box1;
        
        #普通构造函数和复制构造函数的区别。
    


九,静态成员

    1,静态数据成员
    
    2,静态成员函数
        static int volume();
        静态成员函数和非静态成员函数的根本区别时:非静态成员函数有this指针,而静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。
        在c++中,静态成员函数主要用来访问静态数据成员,而不访问非静态成员。
    


十,友元

可以访问与其有好友关系的类中的私有成员,友元包括友元函数和友元类。
    
    1,友元函数
        如果在本类以外的其他地方定义了一个函数(这个函数可以使不属于任何类的非成员函数,也可以使其他类的成员函数),在类体中用friend对其进行声明,此函数就称为本类的友元函数。
        友元函数可以访问这个类中的私有成员。
        1)将普通函数声明为友元函数
        
        #include <iostream>
        using namespace std;
        class Time{
            public:
                Time(int , int , int );
                friend void display(Time &);
            private:
                int hour;
                int minute;
                int sec;
        };
        
        Time :: Time(int h, int m, int s)
        {
            hour = h;
            minute = m;
            sec = s;
        }
        
        void display(Time & t)    //这是普通函数,形参t是Time类对象的引用
        {
            cout << t.hour << " : " t.minute << " : " << t.sec << endl;
        }
        
        int main()
        {
            Time t1(10, 13, 56);
            display(t1);        //调用display函数, 实参t1是Time类对象
            return 0;
        }
        
        输出结果:
        10:13:56
        
        注意:在引用这些私有数据成员时,必须加上对象名。 因为display不是Time类的成员函数,没有this指针,不能默认引用Time类的数据成员,必须指定要访问的对象。
        
        2)友元成员函数
        friend 函数不仅可以是一般函数(非成员函数),而且可以是另一个类中的成员函数。
        还有一个概念 提前引用声明
        
        #include <iostream>
        using namespace std;
        class Date;
        class Time
        {
            public:
                Time (int, int, int);
                void display(Date &);
            private :
                int hour;
                int minute;
                int sec;
        };
        
        class Date{
            public:
                Date(int, int, int);
                
                friend void Time :: display(Date &);
                //声明Time中的display函数为本类的友元成员函数
                
            private:
                int month;
                int day;
                int year;
        };
        
        Time :: Time(int h, int m, int s)
        {
            hour = h;
            minute = m;
            sec = s;
        }
        
        void Time :: display(Date &d)
        {
            cout << d.month << "/" << d.day << "/" << d.year << endl;
            cout << hour << " : " << minute << " : " << sec << endl;
        }
        
        Date :: Date(int m, int d, int y)
        {
            month = m;
            day = d;
            year = y;
        }
        
        int main()
        {
            Time t1(10, 13, 56);
            Date d1(12, 25, 2004);
            t1.display(dl);        //调用t1中的display函数,实现Date类对象d1.
            return 0;
        }
    
    2,友元类
        友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。
        
        在A类的定义体中用以下的语句声明B类为其友元类:friend B;
        
        即  friend 类名;
        关于友元类的2点说明:
        1)友元的关系是单向的而不是双向的。
        2)友元的关系不能传递,如果B类是A类的友元类,C类是B类的友元类,不等于C类是A类的友元类。
        
        在实际工作中,除非的确必要,一般不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数,这样更安全一些。
 

 

十一,模板类

    有两个或多个类,其功能是相同的,仅仅是数据类型不同,可以定义一个类模板,它可以有一个或多个虚拟的类型参数。
    
    template <class numtype>
    class Compare
    {
        public:
            Compare(numtype a, numtype b)
            {x = a; y = b}
            numtype max()
            {return (x > y)? x: y}
            numtype min()
            {return (x < y)? x: y}
        private:
            numtype x, y;
    };
    
    1)声明类模板时要增加一行
        template <class 类型参数名>

    2)原有的类型名int 换成虚拟类型名numtype.
        由于类模板包含类型参数,因此又称为参数化的类。
        类模板是类的抽象,类是类模板的实例。
        
        必须用实际名去取代虚拟的类型,具体做法如下:
        Compare <int> cmp(4, 7);
        类模板名 <实际类型名> 对象名[(参数表)];
        
        说明:
            1)类模板的类型餐宿可以有一个或多个,每个类型前面都必须加class.
            2)和使用类一样,使用类模板时要注意其作用于,只能在其有效作用域内用它定义对象。
            3)模板可以有多层次,一个类模板可以作为基类,派生除派生模板类。

        
    
    
    

面向对象的程序设计

 

    继承和派生

 

一,继承和派生的概念


    父类(old),子类(new)
    子类-->父类   这叫类的继承
    父类-->子类   这叫类的派生
    
    单继承:一个派生类只有一个基类。
    多重继承:一个派生类有两个或多个基类。
    
    派生类是基类的具体化,而基类则是派生类的抽象。


    
二,派生类的声明方式


    “:”
    class 派生类名: [继承方式] 基类名
    {
        派生类新增加的成员
    };

 

三,派生类的成员


    1)从基类接收成员。
        派生类把基类的全部的成员(不炮廓构造函数和析构函数)接收过来,也就是说是没有选择的。
        有些类是专门作为基类设计的,在设计时充分考虑到派生类的要求。
    2)调整从基类接收的成员。
        接收基类成员是程序员不能选择的,但是可以通过指定继承方式来改变基类成员在派生类中的访问属性。
    3)在声明派生类时增加的成员。
        它体现了派生类对基类的功能的扩展。
        在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数时不能从基类继承的。
        
    总结:派生类是基类定义的延续,派生类是抽象基类的具体实现。
    


四,派生类成员的访问属性


    在讨论访问属性时,要考虑以下几种情况:
    1)基类的成员函数访问基类成员。
    2)派生类的成员函数访问派生类自己增加的成员。
    3)基类的成员函数访问派生类的成员。
    4)派生类的成员函数访问基类的成员。
    5)在派生类外访问派生类的成员。
    6)在派生类外访问基类的成员。
    
    1,公有继承
    
    2,私有继承
    
    3,保护成员和保护继承
    
    4,多级派生时的访问属性


    
五,派生类的构造函数和析构函数

 

    1,简单的派生类的构造函数
    
    2,有子对象的派生类的构造函数
    
    3,多级派生时的构造函数
    
    4,派生类构造函数的特殊形式
    
    5,派生类的析构函数


    
六,多重继承


    1,声明多重继承的方法
    
    2,多重继承派生类的构造函数
    
    3,多重继承引起的二义性问题
    
    4,虚基类
        
        1)虚基类的作用
        
        2)虚基类的初始化
        
        3)虚基类的简单应用举例

 

七,基类与派生类的转换

 

八,继承和组合

 

*九,继承在软件开发中的重要意义

 

    多态性和虚函数

 

一,多态性的概念


    polymorphism


    一个事物有多种状态,
    在面向对象方法中一般是这样描述多态性的:向不同的对象发送同一个信息,不同的对象在接收时会产生不同的行为(即方法)。
    也就是说:每个对象可以用自己的方式去相应共同的消息。所谓消息,就是调用函数,不同的行为是指不同的实现,即执行不同的函数。
    


二,例子


三,利用虚函数实现动态多态性


    1,虚函数的作用
    出租车和公交车的例子,动态多态和静态多态。
    虚函数:就是在基类声明函数是虚拟的,并不是实际存在的函数,然后在派生类中才正式定义此函数。
    
    在程序运行期间,用指针指向某一派生类对象,这样就能调用指针指向的派生类对象中的函数,
    而不会调用其他派生类中的函数。
    
    2,静态关联和动态关联
    静态关联:函数重载属于静态关联。在运行前进行关联的,也叫早期关联。
    
    
    3,在什么情况下应当声明虚函数
        1,两点注意:
        1)
        2)
        
        2,考虑因素
        1)
        2)
        3)
        4)
        
    4,虚析构函数


四,纯虚函数与抽象类


    1,纯虚函数
    
    2,抽象类
    
    3,应用实例

 

 

 

 

 

 

    
    
   

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值