zoukankan      html  css  js  c++  java
  • c++类的学习笔记

    用结构体数据的安全性得不到保证。

    使用类对数据进行封装,只能通过函数修改类中的数据

    (1)类的定义

    class 类名
    {
        private:
        protected:
        public: 
    }; 

    private:定义私有成员,只能被类本身的成员函数和友元访问。派生类和其他类均不能访问。若数据没有指明类型,默认为私有。

    public:定义公有成员,可被程序中任何代码访问。

    protected:定义保护成员,能被本身成员函数,友元,派生类访问。

    (2)成员函数的定义

    a、在类中定义

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    class Student
    {
        private:
            string Name;
            float Phi,Math,Ave;
        public:
            void set(string name,float phi,float math)
            {
                Name=name;
                Phi=phi;
                Math=math;
            }
            void Average()
            {
                Ave=(Phi+Math)/2;
            }
            void Display()
            {
                cout<<Name<<" "<<Phi<<" "<<Math<<" "<<Ave;
            }
    };
    
    int main()
    {
        Student stud;
        stud.set("zhangsan",90,100);
        stud.Average();
        stud.Display(); 
        return 0;
    } 

    b、在类外定义

    (考虑到有些函数复杂,在类内写不好看)

    先在类内声明,然后在类外定义的形式是

    函数返回值类型 类名 ::函数名称()

    {}

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    class Date
    {
        private :
            int year,month,day;
        public:
            void setDate(int,int,int);
            bool IsLeap();
            void print()
            {
                cout<<year<<" "<<month<<" "<<day<<endl;
            }
    };
    
    void Date::setDate(int n,int y,int r)
    {
        year=n;month=y;day=r;
    } 
    
    bool Date::IsLeap()
    {
        if(year%400==0||year%4==0&&year%400) return true;
        return false;
    }
    
    int main()
    {
        Date dt;
        dt.setDate(2019,11,22);
        if(dt.IsLeap()) cout<<"yes
    ";
        else cout<<"no
    ";
        dt.print(); 
        return 0;
    } 

    (3)成员的访问

    a、对于数据成员的访问

    对象名.成员名   对象指针名->成员名  (*对象指针名).成员名

    b、对于成员函数的访问

    对象名.成员函数名(参数表)  对象指针名->成员函数名(参数表) (*对象指针名).成员函数名(参数表)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Student
    {
        private :
            string name;
            float Math,Phi,Ave;
        public:
            void setDate(string nam,float math,float phi)
            {
                name=nam;
                Math=math;
                Phi=phi;
            }
            void Average()
            {
                Ave=(Math+Phi)/2;
            }
            void print()
            {
                cout<<name<<" "<<Math<<" "<<Phi<<" "<<Ave<<endl;
            }
    };
    
    int main()
    {
        Student stu,*stud;
        stud=&stu; 
        //一开始我没定义 stu,直接定义个指针用了,这样不行。 
        stud->setDate("zhangsan",100,90);
        stud->Average();
        stud->print();
        return 0;
    } 
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Student
    {
        private:
            string Name;
            int Phi,Math;
        public:
            void setDate();
            void print()
            {
                cout<<Name<<" "<<Phi<<" "<<Math<<endl; 
            }
    };
    
    void Student::setDate()//在类作用域内,直接使用即可访问 
    {
        cin>>Name>>Phi>>Math; 
    }
    
    int main()
    {
        Student stud;
        stud.setDate();
        stud.print();
        return 0;
    } 

    (4)构造函数

    构造函数就是对类内的数据初始化,定义一个类的对象时自动调用,如果不写构造函数,就调用系统默认的构造函数。

    性质:与类名相同 无返回值 可以重载

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Cuboid //长方体类 
    {
        private:
            int length,width,height;
        public:
            Cuboid();//无参构造函数 
            Cuboid(int,int,int);//有参构造函数 
            int volume();//计算体积 
    };
    
    Cuboid::Cuboid()
    {
        length=width=height=1;
    }
    
    Cuboid::Cuboid(int l,int w,int h)
    {
        length=l;
        width=w;
        height=h;
    }
    
    int Cuboid::volume()
    {
        return length*width*height;
    }
    
    int main()
    {
        Cuboid cuboid1;
        cout<<"cuboid1的体积为:"<<cuboid1.volume()<<endl;
        Cuboid cuboid2(10,20,30);
        cout<<"cuboid2的体积为:"<<cuboid2.volume()<<endl; 
        return 0;
    } 

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Cuboid
    {
        private:
            int h,w,l;
        public:
    /*        Cuboid(int hh=10,int ww=20,int ll=30)另一种写法 
            {
                h=hh;w=ww;l=ll;
            }*/
            Cuboid(int hh=10,int ww=20,int ll=30);//声明时有默认参数 
            int volume()
            {
                return h*w*l; 
            }
    };
    
    Cuboid::Cuboid(int hh,int ww,int ll)//不用再写默认参数 
    {
        h=hh;
        w=ww;
        l=ll;
    } 
    
    int main()
    {
        Cuboid cuboid1;
        cout<<cuboid1.volume()<<endl;
        Cuboid cuboid2(1);
        cout<<cuboid2.volume()<<endl;
        Cuboid cuboid3(1,2);
        cout<<cuboid3.volume()<<endl; 
        return 0;
    }

     也可以这样初始化

    Cuboid(int h,int w,int len):height(h),width(w),length(len){}

    (5)拷贝构造函数

    拷贝构造函数的名称与类名一致,函数的形式参数是本类型的一个引用变量。

    Sample (Sample &S);

    对象1=对象2 //对象1和对象2必须是同一个类

    将一个对象的非静态数据成员的值一一赋值给另一对象的对应成员。

    Sample S2(S1);

    Sample S2=S1;两者等价

    a、

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Sample
    {
        private:
            int data;
        public:
            Sample(int dt)
            {
                data=dt;
            }
            void print()
            {
                cout<<data<<endl;
            }
    };
    
    int main()
    {
        Sample s1(100);
        Sample s2=s1;
        s2.print();
    } 

     b、自定义拷贝构造函数 并不是一一赋值

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Sample 
    {
        private:
            int a,b,c,d;
        public:
            Sample(int aa,int bb,int cc,int dd)
            {
                a=aa;b=bb;c=cc;d=dd;
            }
            Sample(Sample &S)
            {
                a=S.a;b=S.b;c=S.c; d=S.d+1; 
            }
            void print()
            {
                cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
            }
    };
     
    int main()
    {
        Sample dt1(1,2,3,4);
        Sample dt2=dt1;
        //Sample dt2(dt1);
        dt2.print();
        return 0;
    }
    

     (6)析构函数

    作用在对象脱离作用域时释放相关资源,清理善后工作。

    析构函数名和类名相同只是在函数名前面加~符号

    无参数 无返回值 只能有一个析构函数 不写虚构函数调用系统自己的

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Cstudent
    {
        private:
            int num;
            string name;
        public:
            Cstudent(string nam,int nnum)
            {
                name=nam;
                num=nnum;
                cout<<name<<" Constructor called.
    ";
            }
            void display()
            {
                cout<<"学号:"<<num<<endl;
                cout<<"姓名:"<<name<<endl; 
            }
            ~Cstudent()
            {
                cout<<name<<" Destructor called
    "; 
            }
    };
    
    int main()
    {
        Cstudent stud1("zhangsan",1);
        Cstudent stud2("lisi",2);
        return 0;
    }

    一般情况下,调用析构函数的次序与调用构造函数的次序相反。

     (7)静态成员--静态数据成员

    静态数据成员被类内所有的对象共享,某个对象对静态数据成员做出修改,则其他所有对象也共享被修改后的值。

    静态数据成员的存储空间不会随着对象的产生而分配,也不会随着对象的消失而释放。

    因此,静态数据成员不能在类体内初始化。

    如果未对静态数据成员赋初值,默认为0;其他成员不会默认为0;

    class Cstudent
    {
        private:
            string name;
            int score;
            static int studenttotal;
            static int sumscore;
        public:
            Cstudent(string nam,int scor)
            {
                name=nam;
                score=scor;
                studenttotal++;
                sumscore+=scor;
                cout<<name<<" Constructor called.
    ";        
            }
            static float average();
            ~Cstudent();
    };
    
    int Cstudent::studenttotal=0;
    
    int Cstudent::sumscore=0;

     (8)静态成员--静态成员函数

    一般情况下,静态成员函数只访问静态成员。也可以访问非静态成员,但要指明其所属对象,但这样麻烦,所以不用。

    class Cstudent
    {
        private:
            string name;
            int score;
            static int studenttotal;
            static int sumscore;
        public:
            Cstudent(string nam,int scor)
            {
                name=nam;
                score=scor;
                studenttotal++;
                sumscore+=scor;
                cout<<name<<" Constructor called.
    ";        
            }
            static float average();//******* 
            ~Cstudent();
    };
    
    int Cstudent::studenttotal=0;
    
    int Cstudent::sumscore=0;
    
    float Cstudent::average()  //********** 
    {
        return (sumscore*1./studenttotal);
    }

    静态成员的访问

    一般是:类名::静态数据成员名

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Cstudent
    {
        private:
            string name;
            int score;
            static int studenttotal;
            static int sumscore;
        public:
            Cstudent(string nam,int scor)
            {
                name=nam;
                score=scor;
                studenttotal++;
                sumscore+=scor;
                cout<<name<<" Constructor called.
    ";        
            }
            static float average();//******* 
            ~Cstudent();
    };
    
    int Cstudent::studenttotal=0;
    
    int Cstudent::sumscore=0;
    
    float Cstudent::average()  //********** 
    {
        return (sumscore*1./studenttotal);
    }
    
    
    
    Cstudent::~Cstudent()  
    {
        studenttotal--;
        sumscore-=score;
        cout<<name<<" Destructor called.
    "; 
    }
    
    int main()
    {
        Cstudent stud[2]={Cstudent("zhangsan",90),Cstudent("wangwu",100)};
        cout<<Cstudent::average()<<endl;
        return 0;
    }

    (9)对象的存储

    只有数据成员占有的内存空间的大小,而没有包括成员函数。

    //类的空间 
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Data
    {
        private:
            int a,b;
        public:
            void setdata(int aa,int bb)
            {
                a=aa;
                b=bb;
            }
            void print()
            {
                cout<<a<<" "<<b<<endl;
            }
        
    };
    
    int main()
    {
        Data x,y;
        cout<<sizeof(int)<<endl;
        cout<<sizeof(x)<<endl;
        return 0;
    } 

    ()

     (10)this指针

    this指针指向正在操作该成员函数的对象。

    this指针最常用的两种情况:

    ①该函数的返回的是对调用该函数的对象的引用 即return *this

    ②当参数与成员变量名相同时,由于参数优先,所以对数据成员必须显式使用this指针修饰。

    //this指针 
    #include<iostream> 
    #include<cstdio>
    using namespace std;
    
    class Point
    {
        private:
            int x,y;
        public:
            Point(int xx,int yy)
            {
                x=xx;y=yy;
            }
            Point& setPoint(int x,int y)
            {
                this->x=x+8;
                (*this).y=y+8;
                return *this;
            }
            int getX(){return x;}
            int getY(){return y;}
    };
    
    int main()
    {
        Point p1(8,8);
        cout<<"执行setPoint()前p1:"<<p1.getX()<<","<<p1.getY()<<endl;
        //cout<<p1.setPoint(8,8);这行是错的 
        p1.setPoint(8,8); 
        //p1=p1.setPoint(8,8);和上一行等价 
        cout<<"执行setPoint()后p1:"<<p1.getX()<<","<<p1.getY()<<endl;  
        return 0;
    

    (11)常对象

    常对象是指对象的数据成员的值不能被改变,常对象必须在定义的同时进行初始化。

    且一旦定义就不能再改变。常对象只能调用const成员函数。普通对象可以调用const成员函数。

    //常对象 
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width;
            int length;
        public:
            Rectangle()
            {
                width=0;
                length=0;
            }
            Rectangle(int w,int len)
            {
                width=w;length=len;
            } 
            int area() const 
            {
                return width*length;
            }
    };
    
    int main()
    {
        Rectangle r1(2,2);
        const Rectangle r2(6,8);
        //Rectangle const r2(6,8);等价 
        cout<<"r1的面积:"<<r1.area()<<endl;
        cout<<"r2的面积:"<<r2.area()<<endl;
        return 0;
    }

    常对象中的某个数据成员想要修改,则声明为mutable

    //常对象 
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width;
            mutable int length;
        public:
            Rectangle()
            {
                width=0;
                length=0;
            }
            Rectangle(int w,int len)
            {
                width=w;length=len;
            } 
            int area() const 
            {
                length*=2;
                return width*length;
            }
    };
    
    int main()
    {
        Rectangle r1(2,2);
        const Rectangle r2(6,8);
        //Rectangle const r2(6,8);等价 
        cout<<"r1的面积:"<<r1.area()<<endl;
        cout<<"r2的面积:"<<r2.area()<<endl;
        return 0;
    }

    指向常对象的指针变量

    const 类名 *指针变量名

    const Rectangle *ptr=&r1;

    不能通过ptr修改r1,但ptr也可以指向别的。

    (12)常数据成员

    将数据成员声明为const型。不能被赋值,类体类外函数只可读。

    对常数据成员的初始化用构造函数的初始化列表。

    const int Length;
    Rectangle(int w,int len):Length(len)
    {Width=w;}

    (13)常成员函数

    这些函数只是可读函数,不改变类的数据成员,对函数加上const关键字标识,提高程序的可读性。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;
                length=len;
            }
            int area()const;
            void print()
            {
                cout<<"print"<<endl;
            }
    };
    
    int Rectangle::area()const
    {
        //width=10;不可修改数据成员 
        //print();常成员函数不能调用非const型成员函数 
        return width*length; 
    }
    
    int main()
    {
        Rectangle r(6,8);
        cout<<r.area()<<endl;
        return 0;
    } 

    (14)常指针

    将指针变量声明为const,这样指针始终保持其初值,不会改变。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;
                length=len;
            }
            int area()
            {
                return width*length;
            }
    };
    
    int main()
    {
        Rectangle r1(6,6);
        Rectangle *const ptr=&r1;
        cout<<ptr->area();
    //    Rectangle r2(3,3);不可以改变常指针的值 
    //    ptr=&r2;
        return 0; 
    } 

    (15)常引用

    一个变量的引用就是这个变量的别名。

    变量名和引用名都指向同一段内存单元。

    如果形参为变量的引用名,实参为变量名,则在调用时虚实结合,

    并不是为形参新开辟了空间,而是把实参变量地址传给形参。

    如果不希望在函数中修改实参的值,则可以把引用变量名声明为常引用。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;
                length=len;
            }
            void setWL(int w,int len)
            {
                width=w;
                length=len;
            }
            int area()
            {
                return width*length;
            }
    };
    
    void setRec(Rectangle &r1)
    {
        r1.setWL(2,2);     
    }
    
    int main()
    {
        Rectangle r(6,8);
        cout<<r.area()<<endl;
        setRec(r);
        cout<<r.area()<<endl;
        return 0;
    }

     若是常引用,则不可以修改。

     (16)友元

    c++用关键字 friend声明类的友元

    ①位于一个函数说明语句之前,指出该函数为这个类的友元函数。

    ②位于一个类名之前,指出该类是这个类的友元。

    如果要允许一个不属于类的函数取该类中的数据

    法一:数据成员声明为共有

    法二:将类内部声明这个函数为友元,可以访问该类数据。

    后者更好。友元其实破坏了类的封装。

    友元函数是普通(全局)函数

    //友元
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;
                length=len;
            }
            int area()
            {
                return width*length;
            }
            friend void display(Rectangle &r1);
    };
    
    void display(Rectangle &r1)//必须要加& 
    {
        cout<<r1.length<<" "<<r1.width<<endl;//不能直接使用length必须通过对象使用 
        cout<<r1.area()<<endl;
    }
    
    int main()
    {
        Rectangle r(6,8);
        display(r);
        return 0;
    } 

    友元函数是其他类的成员函数

    #include<iostream>
    #include<cstdio>
    using namespace std;
    class Rectangle;//提前引用说明
    class Cuboid
    {
        private:
            int Height;
        public:
            Cuboid(int h)
            {
                Height=h;
            }
            int Volume(Rectangle &r);//此处只能声明,不能定义。因为Rectangle类还未定义 
    };
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;length=len;
            }
            friend int Cuboid::Volume(Rectangle &r); 
    };
    
    int Cuboid::Volume(Rectangle &r)
    {
        return r.length*r.width*Height;  
    } 
    
    int main()
    {
        Rectangle R(6,8);
        Cuboid C(20);
        cout<<"长方体的体积为:"<<C.Volume(R)<<endl; 
        return 0;
    } 

    (17)友元类

    C++中允许将一个类声明为另一个类的友元,称为友元类。友元类中的所有成员

    函数都可以访问另一个类中的私有成员或保护乘员

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    class Rectangle;
    
    class Cuboid
    {
        private:
            int Height;
        public:
            Cuboid(int h)
            {
                Height=h;
            }
            int Volume(Rectangle &r);
    };
    
    class Rectangle
    {
        private:
            int width,length;
        public:
            Rectangle(int w,int len)
            {
                width=w;
                length=len;
            } 
            friend class Cuboid;
    };
    
    int Cuboid::Volume(Rectangle &r)
    {
        return r.length*r.width*Height; 
    } 
    
    int main()
    {
        Rectangle r(6,8);
        Cuboid C(20);
        cout<<"长方体的体积为:"<<C.Volume(r);  
        return 0;
    } 

    (18)类模板

    看不下去了。直接抄。

    class A
    {
        private:
            int x,y;
        public:
            A(int xx,int yy){x=xx;y=yy;}
            int sum(){return x+y;}
    };
    
    class A
    {
        private:
            double x,y;
        public:
            A(double xx,double yy){x=xx;y=yy;}
            double sum(){return x+y;} 
    };

    两段代码只是数据类型不同,但做的工作是重复的。

    类模板是一系列相关类的模型或样板,这些类的成员组成相同,成员函数的源代码形式相同。所不同的只是类型。

    (成员的类型以及成员函数的参数类型)。对于类模板,数据类型成了它的参数,因而是一种类型参数化的类。

    类模板是类的抽象,类是类模板的实例。

    template<class T>
    class A
    {
        private:
            T x,y;
        public:
            A(T xx,T yy){x=xx;y=yy;}
            T sum(){return x+y;}
    };

    template<模板参数表>

    class 类模板名

    {}

    
    

    class也可用typename关键字代替 

    类模板不能直接生成对象,因为其参数类型是不确定的,故需要首先对模板参数指定“实参”

    类模板名<具体类型>对象名{(构造函数实参列表)}

    A<int>IntA(6,8);

    A<double>DoubleA(6.6,8.8)

    若函数在类外定义

    T A<T>::sum()

    {return x+y;}

  • 相关阅读:
    从“窃听门”事件解读手机Rootkit攻击
    一款好用的开源信息安全管理系统演示(视频)
    P1908-逆序对
    P1010-幂次方
    P1226-快速幂
    P1433-吃奶酪
    ACM模板——玄学逐字符输入输出
    P1434-滑雪
    P1118-数字三角形
    P1443-马的遍历
  • 原文地址:https://www.cnblogs.com/zzyh/p/11914508.html
Copyright © 2011-2022 走看看