zoukankan      html  css  js  c++  java
  • 对象和类1(六)

    从今天开始,我们将要接触到c++最主要的内容:面向对象编程。

    面向对象编程有以下几个特性:

      抽象:将现实中的事物抽象成类和对象

      封装和数据隐藏:将我们使用的数据封装到类中,我们可以设置哪些数据不能被外界访问。

      继承、多态:在原有类的基础上,创建新的类,根据传入对象类型的不同,执行不同的操作。

    创建自己的类,类包含以下两个部分:

      类声明:以数据成员的方式描述数据部分,以成员函数的方式描述公共接口。提供类的蓝图

      类方法定义:实现类的成员函数。                                                      

    我们将类的声明放在头文件中,类方法定义放在源文件中,在源文件引入类声明的头文件。如Time.h:

    #ifndef TIME_H_
    #define TIME_H_
    
    class Time {
    private :
            int hour ;
            int minute ;
            int second ;
    public :
            void setTime(int h , int m , int s) ;
            int getHour(){
                    return hour ;
            }
            int getMinute(){
                    return minute ;
            }
            int getSecond(){
                    return minute ;
            }
            void setHour(int h) {
                    hour = h ;
            }
            void setMinute(int m ){
                    this->minute = m ;
            }
            void setSecond(int s){
                    this->second = s ;
            }
    
            void print() ;
    } ;
    
    #endif

      Time.h使用#ifndef #define #endif 条件预编译指令,这样可以在多个源文件中包含该类的定义,而不会出现定义多次。

      private: 标示数据是私有成员,外界不能访问,只有本类的成员函数能够使用,public:公有成员,提供外界访问的接口,还有protected,在继承时在讲解。这三个访问控制符。

      声明了Time类,在类内部实现的函数默认是内联函数,也可以不再内部实现,只在实现前加inline也可成为内联函数。如:inline void  Time::print() {}

    在类外实现函数时,要加上Time::  如:

    void Time::setTime(int h , int m , int s ) {

      hour = h ;

      minute = m ;

      second = s ;

    }

    函数内也是类的作用域中,可以直接使用数据成员,外部不再类的作用域中,要加上Time::作用域解析符  标示函数所属类。  

    数据成员可以是基本类型、复合类型、指针、引用等,不能使用Time类型成员,但可以使用Time指针 或引用。

    #include"Time.h"             //引用自定义头文件 "Time.h" 双引号
    #include<iostream>           //引用标准头文件
    
    void Time::setTime(int h ,int m , int s ) {     //Time::
            hour = h ;
            minute  = m ;
            second = s ;
    }
    
    void Time::print(){
            using namespace std ;
    
            cout << "Hour : " << hour << " ,Minute : " << minute << " ,Second : " << second << endl ;
    }
    

     则已经创建了Time类型,我们就可以使用Time来创建自己的对象了。

    #include "Time.h"
    #include<iostream>
    
    int main(){
            Time t ;    //使用默认构造函数创建对象t
            t.setTime(12, 30 , 45) ;     //调用成员函数
            t.print() ;
    
            Time *pt = new Time() ;
            pt->setTime(10, 20 , 30) ;    //指针调用成员函数
            pt->print() ;
    
            delete pt ;
            return 0 ;
    }
    

     类提供了一个特殊的函数:构造函数,用来创建对象,并 把值赋给数据成员,若自己没有定义,则系统会提供默认构造函数,什么也不执行。

    构造函数没有返回值,函数名跟类同名:

    //Time.h 声明
     Time(int h , int m = 0 ,int s = 0) ;   //可以使用默认参数
    
    //Time.cpp
    Time::Time(int h , int m , int s ) {
             hour = h ;
            minute  = m ;
            second = s ;
    }
    
    //main.cpp
    Time t = Time(12 ,23 , 34) ;         //  xian xing diao yong gou zao han shu 
    
    Time t2(7 , 23 , 34 ) ;                  //yin xing diao yong gou zao han shu
    

     当我们自己创建了构造函数后,系统就不再提供默认构造函数Time() ; 了,我们必须使用上面两种方式创建对象,我们也可以通过函数重载定义默认构造函数,即无参构造函数或提供所有默认值的函数。因为有好多地方要用到默认构造函数,所以我们尽量要提供一个。

      析构函数:当用构造函数创建对象后,程序就会跟踪所创建的对象,直到该对象过期,则这时系统会自动调用该对象的特殊函数--构造函数,来完成清理工作。如:构造函数使用new关键字分配内存,则在对象注销的使用应该使用delete来释放内存,则我们可以在析构函数中调用delete来释放内存。

    析构函数:~Time(){}      没返回值    函数名同类名,用~符号,无参            若我们没有定义,则系统会帮我们创建析构函数,不执行任何操作。当我们在构造函数中使用了new来分配内存时,我们应该自己创建一个析构函数。

    Time t(12 , 23, 34 ) ;                创建t对象,并对对象的成员赋值。

    Time t = Time(12 , 23, 34 ) ;          c++标准允许编译器使用两种方式来执行该操作,一种同上面那样,另一种是:调用构造函数创建临时对象,并将该临时对象复制到对象t中,然后丢弃临时对象。      

    Time t1(12 , 23, 34 ) ;   
    Time t2(12 , 23, 34 ) ;   
    
    t1 = t2 ;

      t1 = t2 ;   默认情况下,同结构体一样,将一个对象赋给同类型的另一个对象时,c++将源对象的每个成员的数据复制到另一个对象对应的数据成员中去,若数据成员存在指针,则可能出现两个对象的指针数据成员指向同一块内存,修改一个对象,则会影响另一个对象,则我们应该重写赋值操作符。

    const成员函数

    const T t (12 , 23, 34 ) ;
    t.show() ;            //这行代码不能执行      
    

      t.show()不能执行,因为t对象是const常量,show()成员函数不能保证在函数中是否修改了t对象成员数据。要使之能够执行,则应将show()函数定义为const成员函数。在函数声明和定义后面加const关键字,如:

    //在Time类中声明
    void show() const ;
    
    //在Time.cpp实现
    void Time::show() const {      //在const成员函数中不能修改成员数据
        ////
    }
    

     const成员函数不能修改成员数据,const对象只能调用const成员函数。非const对象既可以调用const成员函数,也可以调用非const成员函数。同将不需要修改的引用参数或指针参数设置为const一样,我们也应该将不需要修改成员数据的函数设置为const成员函数。

     this指针,成员函数中都有个一个this指针,它指向调用该函数的对象本身,我们可以使用它来返回调用对象本身。我们要编写一个比较时间大小的成员函数

    //函数声明
    const Time & Time::maxTime(const Time& t) const  ;
    
    //函数定义
    const Time & Time::maxTime(const Time& t) const {
            if(this->hour == t.hour ){
                    if(this->minute == t.minute ) {
                            if(this->second >= t.second) {
                                    return *this ;       //返回当前对象
                            }else {
                                    return t ;
                            }
                    }else if(this->minute > t.minute ){
                            return *this ;
                    }else {
                            return t ;
                    }
            }else if (this->hour > t.hour ){
                    return *this ;
            }else {
                    return t ;
            }
    }
    

     在const成员函数中,this的类型是指向const的指针,不能通过this来修改对象的数据成员。

    在类中使用常量:

     1:我们可能想到使用const定义常量size,如:

    class T {
       const int size = 30 ;    
    }
    

     但这样是错误的,因为声明类只是描述类的形式,并没有分配内存空间,不能给数据成员赋值。 但我们可以使用参数序列表在创建对象时赋值:

    #include<iostream>
    
    using namespace std ;
    
    class T {
            const int size ;
    public :
            T(int s) : size(s) {} // :size(s) 参数序列表来给size赋值
    int main(){
            T t(4)  ;
            return 0 ;
    }
    

      在创建对象t时,也会创建const int size成员,并用s赋值,      若不使用参数序列表也会出错。如:T(int s ) { size = s }  ;    应该执行到函数内部时,数据size已经定义了,并赋值为默认0,size = s  error   因为size 为const 不能修改了。

       2:使用static 静态成员:因为静态成员,在对象创建之前就已经存在,是所有对象共享的数据。如:

    #include<iostream>
    
    class T {
        static const int size ;  //也可以在这里赋值的     //static 默认是public    
    } ;
    
    const int T::size = 30 ;     //赋值   
    
    int main(){
        std::cout << T.size << std::endl ;
    }
    

      则size即是静态的,也是个常量。

      3:在类中使用枚举:

    class T{
            enum {size = 12 } ;
    
            double cost[size] ;   //size = 12
    };
    

      

  • 相关阅读:
    c# 扩展方法奇思妙用高级篇八:Type类扩展
    Asp.Net 上传大文件专题
    波形捕捉:(2)创建捕捉设备对象
    Capturing Waveforms【译】
    波形捕捉:(1)枚举"捕捉设备"
    C# 调用sql 2000存储过程
    HTTP请求流程(一)流程简介
    Asp.Net 上传大文件专题(4)利用ajax技术显示上传进度
    c# GDI+简单绘图(四)
    波形捕捉:(5)“捕捉缓冲区”信息
  • 原文地址:https://www.cnblogs.com/taxuewuhen/p/3376312.html
Copyright © 2011-2022 走看看