zoukankan      html  css  js  c++  java
  • 第四章 面向对象程序设计的基本特点 课堂笔记

    类和对象
     
     类和对象
    • 类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分。
    • 利用类可以实现数据的封装、隐藏、继承与派生。
    • 利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高。‘
     
    • 新类型的对象该如何被创建和销毁?
      ▫ 构造和析构函数
      ▫ 内存分配和释放函数(operator new、operator new[]、operator delete、operator delete[]) 
     
    *设计class就是设计类型(续)
    • 对象的初始化和赋值有何差别?
      ▫ 复制构造
      ▫ 赋值 
    • 对象作为函数的参数如何以值传递?
     
    4.2.1 类的定义
    类是一种用户自定义类型,声明形式:
    class 类名称
    {
    public:
    公有成员(外部接口)
    private:
    私有成员
    protected:
    保护型成员
    }
    4.2 类和对象  
    4.2.2 类成员的访问控制——公有类型成员
    • 在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。
       私有类型成员在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。如果紧跟在类名称的后面声明私有成员,则关键字private可以省略。
     
    保护类型成员,与private类似,其差别表现在继承与派生时对派生类的影响不同,第七章讲。
     
    对象
    • 类的对象是该类的某一特定实体,即类类型的变量。
    • 声明形式:
    类名 对象名;
    • 例:Clock myClock;
    • 类中成员互访
      ▫ 直接使用成员名
    • 类外访问
      ▫ 使用“对象名.成员名”方式访问 public 属性的成员
     
    类和对象
    类的成员函数
    • 在类中说明原型,可以在类外给出函数体实现,并在函数名前使用类名加以限定。也可以直接在类中给出函数体,形成内联成员函数。
    • 允许声明重载函数和带默认形参值的函数
     
    内联成员函数
    • 为了提高运行时的效率,对于较简单的函数可以
    声明为内联形式。
    • 内联函数体中不要有复杂结构(如循环语句和
    switch语句)。
    • 在类中声明内联成员函数的方式:
      ▫ 将函数体放在类的声明中。
      ▫ 使用inline关键字。
     
    构造函数和析构函数
     
     构造函数
    • 构造函数的作用是在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态         
    • 在对象创建时被自动调用
    • 如果程序中未声明,则系统自动产生出一个默认的构造函数,其参数列表为空
    • 构造函数可以是内联函数、重载函数、带默认参数值的函数
     
    默认构造函数
    • 调用时可以不需要参数的构造函数都是默认构造函数。
    ▫ 当不定义构造函数时,编译器自动产生默认构造函数
    ▫ 在类中可以自定义无参数的构造函数,也是默认构造函数
    ▫ 全部参数都有默认形参值的构造函数也是默认构造函数
    • 下面两个都是默认构造函数,如果在类中同时出现,将产生编译错误:
    Clock();
    Clock(int newH=0,int newM=0,int newS=0);
     
    复制构造函数
    复制构造函数是一种特殊的构造函数,其形参为本类的对
    象引用。作用是用一个已存在的对象去初始化同类型的新对
    象。
    class 类名 {
    public :
    类名(形参);//构造函数
    类名(const 类名 &对象名);//复制构造函数
    ...
    };
    类名::类( const 类名 &对象名)//复制构造函数的实现
    { 函数体 }
     
     
     
    复制构造函数
    • 复制构造函数被调用的三种情况
    ▫ 定义一个对象时,以本类另一个对象作为初始值,发生复制构造;
    ▫ 如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造;
    ▫ 如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象,传递给主
     
    调函数,此时发生复制构造。
     
     
    函数参数尽量传递常引用而不是值
    • 传递对象值会引起复制构造和析构,增加时间空间开销。
    • 传常引用可避免这一问题。以引用做参数时,尽量使用常引用。
     
    隐含的复制构造函数
    如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个隐含的复制构造函数。
    这个构造函数执行的功能是:用作为初始值对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。
     
     
    析构函数
    • 完成对象被删除前的一些清理工作。
    • 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。
    • 如果程序中未声明析构函数,编译器将自动产生一个隐含的析构函数。
     
    编译器默认提供的函数
    class Empty{
    public:
      Empty(){} //这里这个构造函数,应该是,不作任何初始化,类内变量值是随机的
      Empty(const Empty& rhs){…}
      ~Empty(){}
      Empty operator=(const Empty& rhs){…}
    };
     
    有时不应该进行复制和赋值,略》》》》》》
     
    类的组合
     • 类中的成员数据是另一个类的对象。
    • 可以在已有抽象的基础上实现更复杂的抽象。类组合的构造函数设计
    • 原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。
    • 声明形式:

    类名::类名(对象成员所需的形参,本类成员形参) :对象1(参数),对象2(参数),......
    {
      //函数体其他语句
    }
    构造组合类对象时的初始化次序
    • 首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员)进行初始化,初始化次序是成员在类体中定义的次序。
    ▫ 成员对象构造函数调用顺序:按对象成员的声明顺序,先声明者先构造。 ▫ 初始化列表中未出现的成员对象,调用用默认构造函数(即无形参的)初始化
    • 处理完初始化列表之后,再执行构造函数的函数体。

     
     
    UML图形标识
     
     
     
    结构体和联合体
     
    • 结构体是一种特殊形态的类
    ▫ 与类的唯一区别:类的缺省访问权限是private,结构体的缺省访问权限是public
    ▫ 结构体存在的主要原因:与C语言保持兼容
    • 什么时候用结构体而不用类
    ▫ 定义主要用来保存数据、而没有什么操作的类型
    ▫ 人们习惯将结构体的数据成员设为公有,因此这时
    用结构体更方便 
    结构体的定义和初始化
    • 结构体定义
    struct 结构体名称 {
    公有成员
    protected:
    保护型成员
    private:
    私有成员
    };
    • 一些结构体变量的初始化可以用以下形式
    类型名 变量名 = { 成员数据1初值, 成员数据2初值, …… };
     
     
    联合体
    • 声明形式
    union 联合体名称 {
      公有成员
    protected:
      保护型成员
    private:
      私有成员
    };
    • 特点:
    ▫ 成员共用相同的内存单元
    ▫ 任何两个成员不会同时有效
    联合体的内存分配
    union Mark { //表示成绩的联合体
    char grade; //等级制的成绩
    bool pass;
    //只记是否通过课程的成绩
    int percent;//百分制的成绩
    };
     
    无名联合
    例:
    union {
    int i;
    float f;
    }
    在程序中可以这样使用:
    i = 10;
    f = 2.2;
     
    钟表类的代码
    #include<iostream>
    using namespace std;
    class Clock{
        public:
            Clock(int newH= 0, int newM= 0, int newS= 0); //构造函数 
            Clock(const Clock &C); 
            void setTime(int newH= 0, int newM= 0, int newS= 0);
            void showTime(); 
        private:
            int hour,minute,second;
    }; 
    void Clock::setTime(int newH ,int newM,int newS) {
        hour = newH, minute = newM, second = newS; 
    }
    Clock::Clock(int newH , int newM, int newS) {
        hour = newH, minute = newM, second = newS; 
    }
    Clock::Clock(const Clock &C){
        hour = C.hour, minute = C.minute, second = C.second;
    } 
    void Clock::showTime(){
        cout<<hour<<":"<<minute<<":"<<second<<endl;
    }
    int main() {
        Clock myClock;
        myClock.setTime(8, 30, 30);
        Clock NewClock = myClock;
        NewClock.showTime(); 
        myClock.showTime();
        return 0; 
    }

    点类型定义

    #include<iostream>
    using namespace std;
    class Point { //Point 类的定义
        public:
            Point(int xx=0, int yy=0) { x = xx; y = yy; } //构造函数,内联
            Point(const Point& p); //复制构造函数
            void setX(int xx) {x=xx;}
            void setY(int yy) {y=yy;}
            int getX() const { return x; } //常函数(第5章)
            int getY() const { return y; } //常函数(第5章)
        private:
            int x, y; //私有数据
    };
    //成员函数的实现
    Point::Point (const Point& p) {
        x = p.x;
        y = p.y;
        cout << "Calling the copy constructor " << endl;
    } 
    //形参为Point类对象的函数
    void fun1(Point p) {
        cout << p.getX() << endl;
    }
    //返回值为Point类对象的函数
    Point fun2() {
        Point a(1, 2);
        return a;
    }
    //主程序
    int main() {
        Point a(4, 5); //第一个对象A
        cout<<"OOOOO"<<endl;
        Point b = a; //情况一,用A初始化B。第一次调用复制构造函数
        cout<<"11111"<<endl;
        cout  << b.getX() << endl;
        fun1(b); //情况二,对象b作为fun1的实参。第二次调用复制构造函数
        cout<<"22222"<<endl;
        b = fun2(); //情况三,函数的返回值是类对象,函数返回时调用复制构造函数//编译器优化过了,这里不会调用 
        cout<<"33333"<<endl;
        cout  << b.getX() << endl;
        return 0;
    }
       线类:
    //4_4.cpp
    #include <iostream>
    #include <cmath>
    using namespace std;
    class Point { //Point类定义
        public:
        Point(int xx = 0, int yy = 0) {
            x = xx;
            y = yy;
        }
        Point(Point &p);
        int getX() { return x; }
        int getY() { return y; }
        private:
        int x, y;
    };
    Point::Point(Point &p) { //复制构造函数的实现
        x = p.x;
        y = p.y;
        cout << "Calling the copy constructor of Point" << endl;
    }
    
    //类的组合
    class Line { //Line类的定义
        public: //外部接口
            Line(Point xp1, Point xp2);
            Line(Line &l);
            double getLen() { return len; }
        private: //私有数据成员
            Point p1, p2; //Point类的对象p1,p2
            double len;
    };
    //组合类的构造函数
    Line::Line(Point xp1, Point xp2) : p1(xp1), p2(xp2) {
        cout << "Calling constructor of Line" << endl;
        double x = static_cast<double>(p1.getX() - p2.getX());
        double y = static_cast<double>(p1.getY() - p2.getY());
        len = sqrt(x * x + y * y);
    }
    Line::Line (Line &l): p1(l.p1), p2(l.p2) {//组合类的复制构造函数
        cout << "Calling the copy constructor of Line" << endl;
        len = l.len;
    } 
    //主函数
    int main() {
        Point myp1(1, 1), myp2(4, 5); //建立Point类的对象
        Line line(myp1, myp2); //建立Line类的对象
        Line line2(line); //利用复制构造函数建立一个新对象
        cout << "The length of the line is: ";
        cout << line.getLen() << endl;
        cout << "The length of the line2 is: ";
        cout << line2.getLen() << endl;
        return 0;
    }
    将变量和函数限制在编译单元内
    • 使用匿名的命名空间:在匿名命名空间中定义的变量和函数,都不会暴露给其它的编译单元。
    namespace {
    //匿名的命名空间
    int n;
    void f() {
    n++;
    }
    }
    • 这里被“namespace { …… }”括起的区域都属于匿名的命名空间。
     
    标准C++库
    • 标准C++类库是一个极为灵活并可扩展的可重用软件模块的集合。标准C++类与组件在逻辑上分为6种类型:
    ▫ 输入/输出类
    ▫ 容器类与ADT(抽象数据类型)
    ▫ 存储管理类
    ▫ 算法
    ▫ 错误处理
    ▫ 运行环境支持
     
    编译预处理
    • #include 包含指令
    ▫ 将一个源文件嵌入到当前源文件中该点处。
    ▫ #include<文件名>
     按标准方式搜索,文件位于C++系统目录的include子目录下
    ▫ #include"文件名"
     首先在当前目录中搜索,若没有,再按标准方式搜索。
    • #define 宏定义指令
    ▫ 定义符号常量,很多情况下已被const定义语句取代。
    ▫ 定义带参数宏,已被内联函数取代。
    • #undef
    ▫ 删除由#define定义的宏,使之不再起作用。
     
    #if 常量表达式1
    程序正文1    //当“ 常量表达式1”非零时编译
    #elif 常量表达式2
    程序正文2    //当“ 常量表达式2”非零时编译
    #else
    程序正文3    //其他情况下编译
    #endif
     
    #ifdef 标识符
    程序段1
    #else
    程序段2
    #endif
    如果“标识符”经#defined定义过,且未经undef删除,则编译程序段1,否则编译程序段2。
     
    条件编译指令(续)
    #ifndef 标识符
    程序段1
    #else
    程序段2
    #endif
    如果“标识符”未被定义过,则编译程序段1,否则编译程序段2。
     
     
     
     
  • 相关阅读:
    UniEAP V4 开发实践说明文档
    SI_WorkShop_V4安装手册
    unieap platform eclipse.ini vm设置
    asp.net 配置 web.config 禁用VS2013自带的Browser Link功能
    unieap 建库
    onserverclick
    工作中记录的命令和知识点(不断更新)
    CentOS 下做端口映射/端口转发
    DELL服务器硬件信息采集SHELL脚本
    Linux中变量#,@,0,1,2,*,$$,$?的意思
  • 原文地址:https://www.cnblogs.com/SunChuangYu/p/12552152.html
Copyright © 2011-2022 走看看