C++笔记--抽象机制

    •   一个类就是一个用户定义类型
    •   一个结构体也是一种类。(成员函数),由于不一样的结构体中可能会有相同的名字的成员函数,因此咱们在定义成员函数的时候就必须给出有关结构体的名字
      void Data::init(int dd,int mm,int yy){}

       

    •   非成员函数禁止访问私有成员

    •   类中的静态成员:
      •   静态成员--包括函数和成员都必须在类外的某个地方进行定义:格式例如     类型+类名+::+变量名;    double Data::time=1;
        初始化静态变量的时候,无论变量的限定词是什么,都是在类外进行初始化的,private也是如此
      •   静态成员的存取:两种状况。
        第一种:没有对象产生,直接调用。类名::变量名=值。这里必须保证该静态变量为public
        第二种:有对象产生,也是直接调用。类名.变量名=值这里必须保证该静态变量为public
      • (1)出如今类体外的函数不能指定关键字static;

        (2)静态成员之间能够互相访问,包括静态成员函数访问静态数据成员和访问静态成员函数;ios

        (3)非静态成员函数能够任意地访问静态成员函数和静态数据成员;函数

        (4)静态成员函数不能访问非静态成员函数和非静态数据成员;优化

        (5)因为没有this指针的额外开销,所以静态成员函数与类的全局函数相比,速度上会有少量的增加;this

        (6)调用静态成员函数,能够用成员访问操做符(.)和(->)为一个类的对象或指向类对象的指调用静态成员函数。

        url

    •   自引用
      •   每一个非静态函数都知道他是为了哪一个对象而调用的,所以能够显示的引用该对象。
        Date &Date::add_year(int n){
            if(d==29 && m==2 && ;leapyear(y+n)){
                d=1;
                m=3;
            }
            y+=n;
            return *this;
        }

        表达式中的 *this引用的就是找个函数的此次调用所针对的那个对象。大部分的this都是隐含的。对一个类中非静态的成员的引用都要依靠隐式的使用this。格式:this->变量名。。spa

    •   可变的mutable--强制去掉const属性
      •   若是在某个表示中只有一部分容许改变,将这些成员声明为mutable最合适了。
      •   若是一个对象在逻辑上表示为const,可是它的大部分数据成员须要改变,那么最好是将这些须要改变的数据成员放在另外一个独立的对象中,简接访问。

    •   在类内部的函数定义
      •   一个函数若是在类的内部定义和声明,应该是短小简短额,就好像是在线(inline)的同样。
        • 可是在类内部定义的函数有可能会引发一些没必要要的疑虑,因此能够用另外一种的方式进行。例如:把该函数在类外定义成inline函数。


    •   高效的定义数据类型
      •   例如在类中的一个构造函数中写了一些判断这个传递的参数是否合法的判断语句。最好的方法是直接把这些代码写在该构造函数中,最好不要另外写一个函数去包含这些语句。否则太麻烦
      •   增长一些协助函数
      •   重载一些运算符
    •   对象
      •   析构函数
        •   每当一个位于自由存储的对象被删除的时候,都会隐式的调用析构函数
      •   默认构造函数
        •   因为const和引用必须进行初始化,因此含有这两个类型的变量的类就不会有默认构造函数,因此必须本身定义默认构造函数。
        •   一个类若是定义了一个构造函数,就不会自动生成默认构造函数了,这个就必须本身定义默认构造函数了。(通常仍是写上默认构造函数比较好)

      •   构造和析构
        •   局部变量:
          •   对于一个局部变量而言,每当控制走到该局部变量的声明处,构造函数开始做用,当走出局部变量的做用域,析构函数开始做用,(以和构造函数构造顺序相反的书序析构)
            例如 int a,b;构造a,b;析构b,a;
          • 赋值运算符和复制构造函数必须定义清楚,否则很容易形成内存泄漏,删除不干净的问题。
            •   复制构造函数
              table ::table(const table & t){
                  p=new name(sz=t.sz);
                  for(int i=0;i<sz;i++)p[i]=t.p[i];
              }
              
              table &table::operator=(const table& t){
                  if(this!=&t){//小心自赋值  t=t;
                      delete [] p;
                      p=new Name[sz=t.sz];
                      for(int i=0;i<sz;i++)p[i]=t.p[i];
                  }
                  return *this;
              }



        • 成员初始化列表
          •   
            #include<iostream>
            #include<vector>
            #include<stdio.h>
            using namespace std;
            
            class club{
                string name;
                Table members;
                Table ooficers;
                Data founded;
                
                club(const string &n,Data fd);
            };
            club::club(const string &n,Data fd):name(n),members(),ooficers(),founded(fd){
            }

            对于没有默认构造函数的类的成员变量,或者是cosnt,引用类型的成员变量,咱们都要使用成员列表初始化的方式最好,它可以提升效率设计

      • 局部静态存储
        • 例如
          void f(int i){
              static table tal;
              if(i){
                  static table tbl2;
              }
          }
          int main(){
              f(0);
              f(1);
              f(2);
          }
        • 静态变量只会被构造一次,以后便不会再调用构造函数进行构造,析构的方式也是和构造的方式相反
    •   忠告



  • 运算符重载
    •   对于一元的运算符 @,@ a能够解释为a.operator@(),或者是operator@(a).对于后缀的一元的运算符例如++,能够表示为a.operator@(int),或者operator@(a,int)
    •   一个运算符函数要么是一个成员函数,要么至少有一个用户定义类型的参数。注意:若是某个运算符函数想要接受某个内部类型(常量或者是整数),那么这个运算符函数确定不是成员函数。
      例如:加一个复数变量到一个整数a上面,a+2能够写成a.operator+(2),可是2+a写成2.operator+()这个就不对了,违反了+法的规定。
      解决这个问题能够把运算符函数定义成非成员函数,这样就能够十分轻松的解决这个问题。
      •   成员运算符和非成员运算符
        •   通常是只在类自己中定义一些本质上就是须要修改第一个参数值得运算符,例如+=,-=之类的,它的第一个参数必定是变量且须要修改。而像+,-这样的简单的参数运算产生新值得通常就是放在类外进行定义的。
        •  
    •   当咱们遇到一些+法运算时,会出现各类各样的数相加,这个就要咱们去设计不一样的+运算符函数,这里就必需要把加法运算符函数定义为非成员函数
      •   
      •   上面的+=运算符中采用了优化的结构方式,经过减小了临时变量来提升了效率,值的效仿。
    •   复制构造函数
      •   通常比较喜欢采用默认的复制构造函数。这个函数格式:X X(const X &);参数采用的是引用对象,而其余的包含X对象的函数的参数都是采用值对象,不采用引用。
        X a=2;//这里是先创建了X(2),而后去初始化了a
      •   做用:不管是本身写的仍是默认的复制构造函数,都被用来初始化变量(如上),参数传递,值返回,以及异常处理上面。
    •   友元
      •   该函数能够访问类声明的私有部分,friend声明放在private或者public中都能访问私有成员数据。
      •   最主要的是它能最为两个类的成员函数,从而很好的去实现两个类对象之间的操做。
      • 一个类的成员也能够是另外一个类的友元。
      • 友元函数的一些详细做用
      • 2.友元函数的使用指针

        2.1友元函数的参数:code

        由于友元函数没有this指针,则参数要有三种状况:对象

        2.1.1 要访问非static成员时,须要对象作参数;

        2.1.2 要访问static成员或全局变量时,则不须要对象作参数;

        2.1.3 若是作参数的对象是全局对象,则不须要对象作参数;

        2.2友元函数的位置

        由于友元函数是类外的函数,因此它的声明能够放在类的私有段或公有段且没有区别。

        2.3友元函数的调用

        能够直接调用友元函数,不须要经过对象或指针

        2.4友元函数的分类:

        根据这个函数的来源不一样,能够分为三种方法:

        2.4.1普通函数友元函数

        2.4.1.1目的:使普通函数可以访问类的友元

        2.4.1.2语法:

        声明: friend + 普通函数声明

        实现位置:能够在类外或类中

        实现代码:与普通函数相同

        调用:相似普通函数,直接调用

        2.4.1.3代码:

        class INTEGER

         {

          friend void Print(const INTEGER& obj);//声明友元函数

         };

        void Print(const INTEGER& obj)

        {

           //函数体

        }

        void main()

        {

          INTEGER obj;

          Print(obj);//直接调用

        }

        2.4.2Y的全部成员函数都为类X友元函数友元类

        2.4.2.1目的:使用单个声明使Y类的全部函数成为类X的友元,它提供一种类之间合做的一种方式,使类Y的对象能够具备类X和类Y的功能。

        2.4.2.2语法:

        声明位置:公有私有都可,常写为私有(把类当作一个变量)

        声明: friend + 类名(不是对象哦)

        2.4.2.3代码:

        class girl;

        class boy

        {

        public:

          void disp(girl &);

        };

        void boy::disp(girl &x) //函数disp()为类boy的成员函数,也是类girl的友元函数

        {

          cout<<"girl's name is:"<<x.name<<",age:"<<x.age<<endl;//借助友元,在boy的成员函数disp中,借助girl的对象,直接访问girl的私有变量

        }

        class girl

        {

        private:

          char *name;

          int age;

          friend boy; //声明类boy是类girl的友元

        };

        main函数就不写了和普通调用时同样的。

        2.4.3Y的一个成员函数为类X的友元函数

        2.4.3.1目的:使类Y的一个成员函数成为类X的友元,具体而言:在类Y的这个成员函数中,借助参数X,能够直接以X的私有变量

        2.4.3.2语法:

        声明位置:声明在公有中 (自己为函数)

        声明:friend + 成员函数的声明

        调用:先定义Y的对象y---使用y调用本身的成员函数---本身的成员函数中使用了友元机制

        2.4.3.3代码:

        实现代码和2.4.2.3中的实现及其类似只是设置友元的时候变为friend void boy::disp(girl &);本身解决喽……

        小结:其实一些操做符的重载实现也是要在类外实现的,那么一般这样的话,声明为类的友元是必须滴。

        4.友元函数和类的成员函数的区别

        4.1 成员函数有this指针,而友元函数没有this指针。

        4.2 友元函数是不能被继承的,就像父亲的朋友未必是儿子的朋友。

    • 针对大型的对象
      •   大型对象的+法可能会屡次的调用复制构造函数,因此开销会十分的大。为了不过分的复制,咱们通常把对象的参数改成引用,这样开销会小弟

      • 这样确实是减小了开销。
    •   





  • 派生类
    •   派生类
      •   派生类中的基类与派生类的关系:若是drived有一个公共基类base,那么必定能够用drived* 对象给 base* 对象赋值,可是反过来不行,由于一个drived必定是一个base,可是反过来不必定(这里必需要使用强制转换)。
      •   用一个类作基类,这个类必须定义和声明。
      •   派生类可使用基类中的public和protectd属性的成员函数,可是派生类不能使用基类中的private属性的成员。若是想访问private成员,咱们能够设置为protectd属性的,这样除了派生类其余的类和函数都没法访问
      •   构造函数和析构函数:
        派生类中的构造函数:基类中的构造函数的参数应该要在派生类构造函数的定义中有明确的描述。
        • 派生类的构造函数只能描述它本身的成员和本身直接基类的初始式,不能直接去初始化基类的成员

        • 派生类构造函数和析构顺序:构造:基类-成员(按照成员声明顺序)-派生类,,析构:派生-成员(成员声明的反顺序)-基类。
      •   虚函数(多态性)
        •   在某一个虚函数的第一个声明的那个类里面,这个虚函数必须给它定义。(固然除了纯虚函数之外)
        •   在派生类中若是没必要用到这个虚函数的功能,咱们也是能够不写这个虚函数的。
        •   在派生类中使用虚函数能够不用加上virturl这个关键字了。
        •   若是在派生类中存在一个和虚函数同名的、参数类型相同的函数,这个函数就会直接把虚函数的基类版本给覆盖了。调用的时候咱们仍是必须加上做用域限定符::这样才能调用咱们想要的版本
    •   抽象类
      •   若是一个类中有一个或者几个纯虚函数,这个类就是抽象类。其中不可以去建立一个抽象类对应的对象。
      •   抽象类只能做为一个基类,最为一个界面。不去实现任何细节。
    •   通常的类的层次的结构的设计
      •   首先定义一个抽象类。(没有构造函数,定义一个虚析构函数,里面的成员函数所有声明为纯虚函数。)固然派生类是能够实现多重继承的。
      •   
相关文章
相关标签/搜索