zoukankan      html  css  js  c++  java
  • 09.类与对象

    1. 程序抽象与面向对象

    1.1 类与对象的概念与意义

    1.1.1 类的概念与意义

    属性与行为的辩证统一

    1.1.2 程序抽象

    数据封装、信息隐藏

    如果没有类的概念,无法定义非指针量,且控制性不佳

    1.1.3 对象的概念与意义

    对象行为的主动性

    2. 类类型

    2.1 类的声明与定义

    类声明:仅声明类的存在,而不提供 细节

    使用关键字class 示例:class A;

    类定义:一般定义格式

    类成员:数据与函数

    三个保留字顺序任意

    示例:

    class A
    {
        public:       //其后成员公开
        	成员类型 成员名称;
        protected:    //其后成员有限公开
        	成员类型 成员名称;
        private:      //其后成员私有,仅本对象可直接访问
            成员类型 成员名称;
    };
    

    注意:使用class定义类类型时,数据成员与成员函数不写访问控制关键字默认缺省为private;使用struct定义类类型时,数据成员与成员函数默认缺省为public

    2.2 示例

    //点类库接口
    class Point
    {
        public:
            Point(int x, int y);
            ~Point();
            void GetValue(int *x, int *y);
            void SetValue(int x, int y);
            bool Compare(const Point &point);
            char* TransformIntoString();
            void Print();
        private:
        	int x,y;
    }
    

    2.3 关于类声明与定义的说明

    仅限于函数原型使用类类型的声明

    不能用于定义类的数据成员

    示例:

    class B;
    class A
    {
        public:
        	void func(B b);   //正确
        private:
        	B b;              //错误
    };
    class B{ ... };
    

    3. 对象

    3.1 对象的定义与使用

    对象的定义:

    像结构体一样定义和使用对象及其公开的成员

    私有成员不可在对象外部直接访问

    3.2 对象的构造

    3.2.1 对象构造的意义

    构造就是初始化,在定义对象时初始化其数据成员

    3.2.2 对象构造的技术手段:使用构造函数

    与类类型同名,没有返回值类型(包括void类型)

    构造函数允许重载

    构造函数可以带缺省参数,但不建议这么做,会影响判断构造函数真实的参数有几个

    至少公开一个构造函数,因为构造对象是在类的外部做的

    只能由系统在创建对象时自动调用,程序其他部分不能直接调用

    3.2.3 类没有明确的构造函数

    系统会自动产生一个缺省构造函数,自动调用

    缺省构造函数无参数,且函数体中没有任何语句

    如果定义了任意一个构造函数,则不再生成缺省构造函数

    调用缺省构造函数示例

    正确示例:Circle circle;

    错误示例:Circle circle();

    在构造函数无参数时,不能使用函数形式构造对象

    3.2.4 拷贝构造函数

    拷贝构造函数用于构造已有对象的副本

    拷贝构造函数单参数,为本来的常对象的引用

    如未定义,系统自动产生一个缺省拷贝构造函数

    缺省拷贝构造函数为位拷贝(浅拷贝),如需深拷贝(例如成员为指针),需自行定义

    3.2.5 构造函数的初始化列表

    初始化列表的目的与意义

    1. 在构造对象时,同步构造内部对象
    2. 部分成员(常量与引用)只能初始化,不能赋值
    3. 部分成员(类的对象)如果赋值,将导致两次构造
      • 在分配内存时,调用缺省构造函数构造,然后执行构造函数体内的赋值语句再次构造,效率不佳
      • 若类没有缺省构造函数,则会导致问题

    注意事项

    1. 成员初始化按照成员定义顺序,而不是初始化列表顺序
    2. 必须保持初始化列表和成员定义的顺序一致性,但允许跳过部分成员,否则后续成员可能不会正确初始化

    3.3 对象的析构

    意义

    析构就是终止化,在对象生命期结束时清除它

    对象析构的技术手段:使用析构函数

    • 与类类型同名,前有”~“记号,无返回值类型(包括void类型),无参数
    • 析构函数必须是公开的
    • 可以由系统在销毁对象时自动调用,也可以由程序其他部分直接调用,但两者工作原理不同
    • 每个类只能有一个析构函数
    • 若未定义,系统会产生一个缺省析构函数,该函数无代码

    定义析构函数的目的

    • 用于构造对象中动态分配内存的目标数据对象

    示例

    class A{
    	public:
    		A(int x);
    		~A();
    	private:
    		int *P;
    };
    A::A(int x){
    	p = new int;
        *p = x;
    }
    A::~A(){
        delete p;
        p == NULL;
    }
    

    3.4 对象数组

    像普通数组一样定义和使用

    3.4.1 对象数组的初始化

    • 当构造函数单参数时,像普通数组一样构造所有元素
    • 当构造函数多参数时,使用下述方法构造

    Circle circle[2] = {Circle(1.0,0.0,0.0),Circle(2.0,1.0,1.0)};

    4. 类与对象的成员

    4.1 内联函数

    目的:程序优化,展开函数代码而不是调用(当函数体较为简单时,多次函数调用的开销远大于直接执行函数本身的,这时适合使用内联函数)

    内联函数使用的注意事项

    • 在函数定义前添加inline关键字,仅在函数原型前使用此关键字无效
    • 编译器必须能看见内联函数的代码才能在编译期展开,因而内联函数必须实现在头文件中
    • 在类定义中给出函数体的成员函数自动成为内联函数
    • 函数体代码量较大,或包含循环,不要使用内联
    • 构造函数和析构函数有可能隐含附加操作,慎用内联
    • 内联函数仅是建议,编译器会自主选择是否内联

    4.2 常数据成员

    常数据成员:值在程序运行期间不可变

    • 定义格式:const 类型 数据成员名称;
    • 初始化:只能通过构造函数中的初始化列表进行

    示例:

    class A
    {
        public:
    	    A(int a);
        private:
        	const int num;
    };
    A::A(int a):num(a){......};
    

    4.3 常成员函数

    常成员函数:不能修改对象成员值的函数

    • 定义格式:类型 成员函数名称(参数列表) const;
    • 常成员函数不能调用类中非常成员函数,因为可能修改对象成员值
    • 静态成员函数不能定义为常成员函数
    • 如果对象为常量,则只能调用其常成员函数

    示例:

    class Circle{
        public:
        	double GetArea() const;
    	    ......;
    };
    double Circle::GetArea() const{......}
    

    4.4 静态数据成员

    静态数据成员只有一份,由该类所有对象共享

    • 声明格式:static 类型 静态数据成员名称;
    • 仅声明,不在对象上分配空间
    • 定义格式:类型 类名称::静态数据成员名称 = 初始值;
    • 必须在外部初始化,初始化动作与访问控制无关,初始化动作放在源文件,而非头文件

    示例:

    class A
    {
        private:
        	static int count;
    };
    int A::count = 0;
    

    4.5 静态成员函数

    • 在类而不是对象上调用
    • 目的:访问类的静态数据成员,若要访问类的非静态数据成员,必须指定对象或者使用指向对象的指针

    示例:

    class A
    {
        public:
        	static int f();
    	    static int g(const A &a);
        private:
        	static int count;
         	int num;
    };
    int A::count = 0;
    int A::f(){
        return count;
    }
    int A::g(const A &a){
        return a.num;
    }
    

    4.6 静态常数据成员

    静态常数据成员:值在程序运行期间不可变且只有唯一副本

    • 定义格式:static const 类型 数据成员名称;
    • 初始化:只能在类的外部初始化

    示例:

    class A{
        private:
        	static const int count;
    };
    const int A::count = 10;
    

    4.7 友元函数与友元类

    友元:破坏类数据封装与信息隐藏

    • 类的友元可以访问该类对象的私有与保护成员
    • 友元可以是函数、其他类成员函数,也可以是类
    • 定义格式:friend 函数或类声明;
    • 两个类的友元关系不可逆,除非互为友元(如下例,Globe可以访问Circle中的私有成员,但Circle未必可以访问Globe的私有成员,除非Globe也将Circle设为友元)

    示例:

    class Circle{
    	friend double Get_Radius();
        friend class Globe; //将Globe类所有成员函数声明为友元
        private:
        	double radius;
    };
    

    5. 继承

    5.1 继承与派生

    继承的基本概念

    • 类类型:描述分类的概念
    • 继承:描述类之间的血缘(继承)关系
    • 基类、派生类
    • 父类、子类(不恰当的概念)

    继承的意义

    • 派生类拥有基类的全部属性与行为
    • 派生类可以增加新的属性与行为,不能删除原有的属性的行为

    5.2 单继承

    单继承的基本语法格式

    class 派生类名称:派生类型保留字 基类名称{......};

    派生类型保留字

    • public:基类的public、protected成员在派生类中保持原有访问控制,private成员在派生类中不可见(属于基类隐私)
    • protected:基类的private成员在派生类中不可见,public、protected成员在派生类中变为protected成员
    • private:基类的private成员在派生类中不可见,public、protected成员在派生类中变为private成员
    • 设计类时若需要使用继承机制,建议将派生类需要频繁使用的基类数据成员设为protected的

    5.3 多继承

    多继承的基本语法格式

    class 派生类名称:派生类型保留字 基类名称1,派生类型保留字 基类名称2,...{...};

    多继承示例

    class A {...};
    class B {...};
    class C:public A, protected B{..};
    

    多继承可能导致的问题:派生类中可能包含多个基类副本,要慎用

    5.4 虚继承

    虚拟继承的目的

    • 取消多继承时派生类中公共基类的多个副本,只保留一份
    • 格式:派生时使用关键字virtual

    使用示例:D中只有A的一份副本

    class A {public: void f();};
    class B:virtual public A {public: void f();};
    class C:virtual public A {public: void f();};
    class D:public B,public C {public: void f();};
    

    5.5 派生类的构造函数与析构函数

    构造函数的执行顺序

    1. 调用基类的构造函数,调用顺序与基类在派生类中的继承顺序相同
    2. 调用派生类新增对象成员的构造函数,调用顺序与其在派生类中的定义顺序相同
    3. 调用派生类的构造函数

    析构函数的执行顺序

    1. 调用派生类的析构函数
    2. 调用派生类新增对象成员的析构函数,调用顺序与其在派生类中的定义顺序相反
    3. 调用基类的析构函数,调用顺序与基类在派生类中的继承顺序相反

    5.6 类的赋值兼容性

    共有派生时,任何基类对象可以出现的位置都可以使用派生类对象代替

    • 将派生类对象赋值给基类对象,仅赋值基类部分
    • 用派生类对象初始化基类对象引用,仅操作基类部分
    • 使指向基类的指针指向派生类对象,仅引领基类部分

    保护派生与私有派生不可以直接赋值

    • 尽量不要使用保护派生与私有派生(因为无法赋值初始化对象)

    6. 多态

    多态性

    • 目的:不同对象在接收到相同消息时做不同响应
    • 现象:对应同样成员函数名称,执行不同函数体

    多态性的实现

    • 虚函数:使用virtual关键字声明成员函数
    • 声明格式:virtual 函数返回值 函数名称(参数列表);
  • 相关阅读:
    jquery获得option的值和对option进行操作
    laravel 在添加操作自动完成对时间保存修改
    laravel使用ajax
    mysql操作查询结果case when then else end用法举例
    Laravel框架数据库CURD操作、连贯操作总结
    laravel5.1关于lists函数的bug
    详解AngularJS中的filter过滤器用法
    javascript中的时间处理
    angularJs--$on、$emit和$broadcast的使用
    angularJs--<ui-select>
  • 原文地址:https://www.cnblogs.com/bear-Zhao/p/13787177.html
Copyright © 2011-2022 走看看