zoukankan      html  css  js  c++  java
  • c++面向对象程序设计总结(类的使用)

    本篇算是学习c++有关类的知识的一些易错点吧.....

    并不是特别详细,以后会更新吧....

    几点并不关于类的东西

    1.函数模板,用虚拟类型来实现模板的功能

    #include<iostream>
    using namespace std;
    template <typename t>//t为虚拟类型的名字,自己起的
    t maxx(t a,t b,t c)
    {
        return max(a,max(b,c));
    } 
    
    int main()
    {
        double a=1.1,b=2.2,c=3.3;//不管为double 还是int都可以调用maxx 
        cout<<maxx(a,b,c)<<endl;
        int a1=1,b1=2,c1=3;
        cout<<maxx(a1,b1,c1)<<endl;
     } 

    2.关于函数默认的参数值要放到最右边

    void f1(float a,int b=0,int c,char d='a');//错误,
    void f2(float a,int c,int b=0,char d='a');//正确 

    3.内置函数

    函数最左边加上inline(我觉得没啥用),规模很小的函数才用

    4.字符串

    sizeof(string) 为4,因为系统分配的是固定的字节数,存放的是字符串的地址

    .......(以后再补充把)

    开始类的学习

    1.三种类的类型

    public

    这个就不多说了,类的对外接口

    private

    想要访问只能通过该类中的函数来访问

    protected

    和private差不多,区别在于继承时,以后说

    2.类的声明和成员函数的分离(以后更新)

    3.构造函数

    没有返回值,名字和类名字一样#include<iostream>

    using namespace std;
    class box{
        public:
            box(int ,int ,int );//构造函数 (有无默认参数都行)
            int volume();
        private:
            int h;
            int w;
            int l;
    };
    box::box(int a,int b,int c)
    {
        h=a,w=b,l=c;
    }
    //其实一般这样写
    // box::box(int a,int b,int c):h(a),w(b),l(c){}
    //注意如果是数组的话 则要写在大括号内
    //box::box(int a,int b,int c,char nam[]):h(a),w(b),l(c)
    //{strcpy(name,nam);}
    
    

    可以用另一个对象初始化另一个

    time t1;

    time t2=t1;   //注意是吧t1的数据成员复制到t2,而不调用t2的构造函数

    4.析构函数

    注意一点,先构造的后析构,相当于栈,先进后出

    静态局部对象,在函数结束时,并不释放,也就不调用析构函数

    5.对象数组

    box b[3] = (1 , 2 ,3)//这样其实不对,这三个实参则分别作为3个元素的第一个实参

    初始化应该

    box a[3]={
        box(10,20,30);
        box(20,30,40);
        box(1,2,3);
    }

    6.对象指针

    先说下函数指针。。。。还有函数指针????

    类型名(* 指针变量名)(参数列表)

    void (* p)();//p是一个指向void型函数的指针 
    p=fun;//fun函数入口地址付给p 注意没有括号
    (*p)();

    对象成员函数有些复杂

    要求    函数参数类型和个数匹配        函数返回值类型一样     所属的类一样

    void ( time:: *p )();//此时p为指向time类中的成员函数指针

    time t;
     void (time:: *p)();
     p = &time::gettime();
     (t.*p)();

    7.this指针(指向当前对象)

    当前被调用的成员函数所在对象的起始地址

    int box::volume()
     {return (h*l*w);}//实际为{ return this->h * this->l * this->w;}

    调用时 如 a.volume() ,实际为将对象a的地址传给形参this指针

    8.常对象
    只能通过构造函数参数表来对其初始化,所有数据成员绝对不能被改变,并且只能调用它的常成员函数
    如果非要改变,要加上 mutable 如有一个计数变量count, 则要 mutable int count;

    非const数据成员 非const函数可引用和改变 const函数可引用不可改变
    const数据成员 非const函数可引用不可改变 const函数可引用不可改变
    const函数不可调用非const函数

    常指针 如
    Time t1;
    Time * const p = =&t1;
    p不可再改变
    常变量只能被常指针指向,,
    普通变量也可被常指针指向,但这时该普通变量就在这期间变成的常变量,不能改变

    复制构造函数
    Box box2(box);


    9.静态数据成员

    数据声明前 加 static
    特点是可以被每个该同类对象所引用,只能在类体外进行初始化,在类外也可直接引用
    如 int Box::height = 10;//不必加static
    可以通过对象名来引用,也可以通过类名

    cout<<a.count<<endl;
    cout<<Box::count<<endl;

    10.友元
    友元函数可以使一般的,也可以是另一个类中的,可以访问私有数据成员
    友元类就是全家都是友元函数
    注意是单向的,注意不能传递

    11.类的模板

    temple<class t>//t 为虚拟变量名字 可以有多个,但都要加class 如:temple<class t1,class t2> 
    class compare{
    public:
    compare(t a,t b)
    {
    x=a,y=b;
    }
    t max() {
    return max(a,b);
    }
    private:
    t x,y;
    }; 


    定义对象时为:
    compare<int> cmp(3,4);
    //多个时 compare<int ,double> cmp(3,4);


    12.对运算符的重载

    class yuan{
        public:
            yuan(double a,double b):x(a),y(b){};
            yuan operator +(yuan &t)
            {
                return yuan(x+t.x, y+t.y);
            }
        private:
            double x,y;
    };             

    此时如果有
    yuan c1(1,2),c2(1,2),c3;
    c3 = c1 + c2;
    则实际为 c3 = c1.operator(c2);

    但其实我觉得更方便的是通过友元函数

    class yuan{
        public:
            yuan(double a,double b):x(a),y(b){};
            friend yuan operator +(yuan &t1,yuan &t2)//这个其实挺灵活的,可以自行改变 
            {
                return yuan(t1.x+t2.x, t1.y+t2.y);
            }
        private:
            double x,y;
    };             

    c3 = c1 + c2 则解释为operator +(c1,c2);

    13.继承

    派生类拥有基类的数据成员,其分配如下

    先说公有继承

    基类属性                               派生类    

    private                                  不可访问

    public          公有继承后        public

    protected                            protected

    私有继承

    基类属性                               派生类    

    private                                  不可访问

    public          私有继承后        private

    protected                            private

    保护继承

    保护成员:只有子女(派生类)可以访问,(友元函数也不行)

    基类属性                               派生类    

    private                                  不可访问

    public          保护继承后        protected

    protected                            protected

    14.有子对象的派生构造函数

    #include<iostream>
    using namespace std;
    class Student{
        public:
            void display();
            Student(int n,string nam):num(n),name(nam){}
        protected:
            int num;
            string name;
    };
    class Student1: public Student{
        public:
            Student1(int n,string nam,int n1,string nam1,int a,string ad):
                Student(n,nam),monitor(n1,nam1),age(a),addr(ad){}//注意初始化,一般用初始化表来 ,同样的,在多级派生中也是如此来构造
            void show()
            {
                monitor.display();
            }
        protected:
            Student monitor;//派生类中的子对象 
            int age;
            string addr;
    };
    int main()
    {
        
     } 

     多级的形式

    派生类构造名: 基类1构造函数(参数表) , 基类2构造函数(参数表) , 基类3构造函数(参数表) 

    {  派生类中新增的数据成员初始化语句 }

    15 . 关于多重继承的二义性问题

    就是继承的函数名  和   派生的函数名一样了

    假设有类A和类B,此时类C同时继承类A和类B,现在问题是  类A 类B  类C都有一个  叫display()的函数 

    C c1;

    c1.display()//此时该是谁呢,是最新的也就是c的display()。这个会覆盖

    此时要想访问A的display(),则要限定作用域 。

    比如  c.A::display();

    16.虚基类

     

    D 是 B 和 C 的派生类,B 和 C 又都是继承了A,这样会保留多份数据成员的拷贝

    虚基类是的在继承简介共同基类时只保留一份

    class A
    {
        A(int i){}
        .....
    };
    class B: virtual public A
    {
        B(int n):A(n){}
        ...
    };
    class C: virtual public A
    {
        C(int n):C(n){}
        ...
    };
    class D:public B,public C
    {
        D(int n):A(n),B(n),C(n){}//这个必须由最后的派生类中对直接基类和虚基类初始化
    }

    17.类型的转化

    派生类可以向基类对象赋值  (大材小用),也可以向积累对象的引用进行赋值或初始化

    派生类对象的地址可以赋给基类对象的指针变量,也就是说,指向基类对象的指针变量也可以用来指向派生类对象

    18.多态性

    分为两种 ,静态多态性和动态多态性(啥玩意啊,玩的怪花(小声bb))

    静态多态性 就是  函数重载   和运算符的重载

    动态  就是通过虚函数来实现的

     说一下虚函数,作用还是要解决继承中的二义性问题,

    解决方法是想通过指针的方法来实现

    Student stu(...);
    Graduate grad(...);//假设grad是stu的派生,且两者都有display函数
    Student *p = &stu;
    p->display();
    p = &grad;//想通过变换指针指向来,但单单的这样做是不行的,因为这样做会把grad类型强制转化成student的类型 
    p->display();

    解决上述问题的方法是将Student类中的display()函数前加上virtual

      注意问题是  成原函数 定义为虚函数后,其派生类都为虚函数

      使用方法是指向一个基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象

     

    19.虚析构函数

    如下面代码

    class Point{
        public:
            point();
            ~point();
    }; 
    class Circle: public Point
    {
        public:
            Circle();
            ~Circle();
    }
    int main()
    {
        Point *p = new Circle;
        delete p;
        return 0;
    }

    new的一个对象,在释放的时候,只会执行基类的析构函数,而不执行派生类的

    解决方法是  在Point 的析构函数前加上 virtual

    个人理解(这个virtual  在继承中 都会遗传)

    20.纯虚函数

    先说一点吧,往往有一些类,他们不用来生成对象,唯一目的就是用它去建立派生类,叫做抽象类

    比如,点 可以派生出 园 ,圆可以派生出圆柱体  ,但这些都是 shape 的直接派生或者间接派生

    比如

    class Shape{
        public:
            virtual float area() const {return 0.0;}//虚函数
            virtual float volume() const {return 0.0;}//虚函数
            virtual void shapeName() const = 0; // 纯虚函数 形式为 virtual 函数类型 函数名字 (参数列表) =0;
    };

    最后来个差不多的

    #include<iostream>
    using namespace std;
    class Shape
    {
        public:
            virtual float area() const {return 0.00;}
            virtual float volume() const {return 0.00;}
            virtual void ShapeName() const = 0;
    };
    class Point: public Shape
    {
        public:
            Point(float a=0,float b=0): x(a), y(b){};
            void SetPoint(float a,float b)
            {
                x=a,y=b;
            }
            float getX() const {return x;}
            float getY() const {return y;}
            
            virtual void ShapeName() const {cout<<"point"<<endl;}
            friend ostream &operator <<(ostream &,const Point &);
        protected:
            float x,y;
    };
    ostream &operator <<(ostream &output,const Point &p)
    {
            output<<"["<<p.x<<","<<p.y<<"]"<<endl;
            return output;
    }
    class Circle: public Point
    {
        public:
            Circle(float x=0,float y=0,float r=0):Point(x,y),radius(r) {}
            
            void SetRaidus(float r){ radius = r;}
            
            float GetRadius() const {return radius;}
            
            virtual float area() const{ return 3.14 * radius * radius;}
            
            virtual void ShapeName() const {cout<<"Circle"<<endl;}
            
            friend ostream &operator <<(ostream &,const Circle &);
            protected:
                float radius;
    };
    ostream &operator <<(ostream &out,const Circle &c)
    {
        out<<"["<<c.x<<" "<<c.y<<"]"<<endl;
        out<<"r="<<c.radius<<endl;
        return out;
    }
    class Yuan: public Circle
    {
        public:
            Yuan(float x=0,float y=0,float r=0,float h=0):Circle(x,y,r),height(h){}
            
            void SetHeight(float h) {height = h;}
            
            virtual float area() const {return 2 * Circle::area() + 2 * 3.14 * radius * height;}
            
            virtual float vulume() const {return Circle::area() * height;}
            
            virtual void ShapeName() const {cout<<"Yuan"<<endl;}
            
            friend ostream &operator <<(ostream &,const Yuan &);
        protected:
            float height;
    };
    ostream & operator <<(ostream &out,const Yuan &Y)
    {
        out<<"["<<Y.x<<" "<<Y.y<<"],r="<<Y.radius<<"H="<<Y.height<<endl;
        return out;
    }
    
    int main()
    {
        Point point (3.2,4.5);
        Circle circle(2.4,1.2,5.6);
        Yuan yuan(3.4,6.4,5.2,10.5);
        point.ShapeName();
        cout<<point<<endl;
        
        circle.ShapeName();
        cout<<circle<<endl;
        
        yuan.ShapeName();
        cout<<yuan<<endl;
        
        Shape *pt;
        pt=&point;
        pt->ShapeName();
        
        pt=&circle;
        pt->ShapeName();
        pt=&yuan;
        pt->ShapeName();
        return 0;
    }

    可能以和还会更新吧..............

  • 相关阅读:
    KDiff
    如何用Javascript检测到所有的IE版本
    Chrome中的哪些端口是限制使用的?
    如何防止XSRF攻击
    External component has thrown an exception
    OpenGL中的原子操作需要注意的地方
    Unable to create new web application
    How to Redirect in ASPNET Web API
    图形转换的组合(注意从右向左读)
    如何用Client OM获取页面上一个Content web part的内容
  • 原文地址:https://www.cnblogs.com/wpbing/p/9774818.html
Copyright © 2011-2022 走看看