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\n";
    else cout<<"no\n";
    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.\n";
        }
        void display()
        {
            cout<<"学号:"<<num<<endl;
            cout<<"姓名:"<<name<<endl; 
        }
        ~Cstudent()
        {
            cout<<name<<" Destructor called\n"; 
        }
};

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.\n";        
        }
        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.\n";        
        }
        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.\n";        
        }
        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.\n"; 
}

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;}

posted @ 2019-11-22 22:12  ANhour  阅读(472)  评论(0编辑  收藏  举报