我的c++面向对象学习之路

多文件链接

  1. 命令行
  2. make的使用

变量定义

  1. auto的使用 相关学习网址
  • 机理:根据后面的赋值,推测变量类型
  • 作用:简化变量初始化的书写,例如迭代器
  • 注意:
    • 变量必须初始化(即赋值)
    • auto是占位符,不可用于类型转换,例sizeof和typeid
    • 同一个auto里面只能定义一种类型
    auto x1 = 5, x2 = 5.0, x3='r';// This is too much....we cannot combine like this
    
  1. 指针 new/delete 相关学习网址
  • 这两个操作与sizeof一样不是函数
  • 与malloc的区别:malloc不可用于初始化
  • 例:
    int *a1=new int;
    int *a2=new int[10];
    delete a1;
    delete[]a2;
    
  1. 左值引用 相关学习网址
  • 格式:
    int v0;
    int &v1=v0;
    
  • 前提:旧变量已经占有内空间,即右侧值能够取地址,若无法取地址,则用常引用
    const int &t=10;
    //相当于
    const int temp=10;
    const int &t=temp;
    //const 使得temp指向的地址只可存为10这个值,只可读,不可改变
    
  • 作用:可使得多层嵌套时,方便阅读,例用于结构变量
    int t=a.b.c;
    //等价于
    int &temp=a.b;
    int t=temp.c;
    
  • 注:函数的返回值可以是引用类型,但不可是函数临时变量
  1. 右值引用 相关学习网址
  • 特点:不可取地址、没有名字的就是右值
  • 格式:
    int && sum=3+4;
    float && res=ReturnValue(f1,f2);//将函数的返回值保存下来
    void ReturnValue(T && s,T && t){...}
    
  • 作用:减少临时变量拷贝的开销

变量的初始化、类型的推导、基于范围的for循环

  1. 初始化列表
    int a[]={1,2,3};
    //等价于
    int a[]{1,2,3};//列表的初始化中,花括号前的等号可省略
    
  2. 初始化变量
    int a=3+5;
    int a={3+5};
    int a(3+5);
    int a{3+5};
    int *i=new int(10);//i指向的内存中有个初始值10
    double *q=new double{1.2f};
    
  3. 变量类型的推导
    struct{char *name;} anon_u;
    struct{int d;decltype(anon_u)id;} anon_s[100];//匿名的struct数组
    int main{
    decltype(anon_s)as;
    cin>>as[0].id.name;
    ...
    }
    //decltype的用法:https://blog.csdn.net/u014609638/article/details/106987131/
    
  4. 基于范围的for循环
    int arr[]={1,2,3};
    for(auto e:arr) cout<<e<<endl;
    

函数的重载

  • 注意:保证各个函数的参数不同

  • 例:

    void print(int a){
        cout<<a<<endl;
    }
    void print(string str){
        cout<<str<<endl;
    }
    

函数参数的缺省值与追踪返回类型的函数

  1. 函数参数的缺省值
  • 适用情形:函数参数一般有一个固定值

  • 注:只可放在函数的最后几个参数(若有n个参数,k个可直接赋值,则第n-k+1~n个参数是直接赋值的)

  • 例:

    void print(char* msg = "hello"){
        cout<<msg<<'#';
    }
    int main(){
        print("Berjing...");
        print();
        return 0;
    }
    //输出Beijing。。。#hello#
    
  1. 追踪返回类型的函数
  • 普通声明:

    int func(char *ptr,int val);
    
  • 追踪返回类型的函数声明:

    auto func(char *ptr,int val) -> int;
    auto func(char *ptr,int val);//这种写法的正确性有待指正
    
  • 作用:若函数返回值未知,且需根据函数参数推导,则可使用这种写法

    template<typename T1, typename T2>
    auto Sum(T1&t1, T2& t2) -> decltype(t1+t2){
        return t1+t2;
    }
    

类的定义

  • 自定义类型,包含函数与数据

  • 类中函数——成员函数

  • 类中成员——数据成员

  • 类的成员(数据、函数)可拥有不同的访问权限

  • 权限种类:public、private、protected

    • 访问权限
    class Matrix{
    public:
    	void fill{char dir);
    private:
    	int data[6][6];
    };
    class Matrix{
    	int data[6][6];
    public:
    	void fill{char dir);
    };
    
  • 对象:用类定义的变量

  • 调用形式:对象名.成员名(仅限public)

  • 类外定义成员函数时,要加类名限定,格式:类名::函数名( :: 域运算符)

  • 成员函数的两种定义:

    //(1)在类内定义成员函数
    Class Matrix{
    Public:
    void fill(char dir){;
    }
    };
    //(2)在类外定义成员函数
    Void Matrix::fill(char dir){;
    };
    
  • 类中默认一个指针this(编译器产生),指向本身对象存放的地址,用”->”访问

  • 友元函数:

    • 可访问类的private成员
    • 特点:
      1. 会破坏封装性
      2. 与声明位置无关
    • 类型:friend 函数原型;

构造函数

  1. 默认构造函数(无参数)
  • 在定义元素为对象的数组时(ClassName array_var[NUM];),类必须声明默认构造函数的定义,即在类里必须写上ClassName(){…;}(省略号中内容可有可无)
  • 使用默认构造函数(无参)生成对象时,格式:ClassName 变量;(变量后不可有括号)
  • 还可以通过ClassName()=default;来构造
  • 构造函数
  1. 可使用初始化列表初始化成员数据 相关学习网址
  • 形式:以冒号开头,后跟一系列以逗号分隔的初始化字段,每个数据成员后跟一个放括号中的初始化式

    Class ClassName{
    publicint a;
        string b;
        ClassName():a(0),b("aba")
        {}//这个大括号不可以忘
        //上下两种实质上等价
        ClassName(){
            a=0;
            b{"aba"};
        }
    };
    
  1. 委派构造函数:可调用其他构造函数

    class Info{
    public:
        Info(){Init();}
        Info(int i):Info(){id=i;}
        Info(char c):Info(){gender=c;}
    private:
        void Init(){...;}
        int id {2016};
        char gender{'M'};
        ...;
    };
    
  2. 析构函数:一种成员函数

  • 形式:~ClassName();

  • 特点:

    1. 没有函数返回值
    2. 没有参数
    3. 一个类只有一个析构函数
    4. 若不写则系统默认生成
  • 调用时间及对象:编译器在对象生命期结束时自动调用

  • 作用:释放占用资源,或其他后期处理

    class String{
    private:
        char* p;
    public:
        String(int n);
        ~String();
    }
    String::~String(){
        delete[]p;
    }
    String::String(int n){
        p=new char[n];
    }
    
  1. 拷贝构造函数:一种特殊的构造函数
  • 用于初始化,以自身类类型的常量引用作为第一个参数,而编译器会根据这个自动拷贝生成一个新对象,且其额外参数都有默认值

    class Person{
        int id;
        ...;
        public:
        Person(const Person& src){id=src.id;...;}
        ...;
    };
    

运算符重载

  1. 赋值运算符重载:一种特殊成员函数 相关学习网址
  • 实现

    ClassName& operator= (const ClassNAme& right){
        if(this != &right){//避免自己赋值给自己
        //将right对象中的内容复制到当前对象中
    
         *this;
    }
    
  • 函数名:operator=

  • 参数:right,即等号右侧的变量的常量引用(常量:防止函数对right进行改变;引用:避免函数调用时对实参的拷贝,提高了效率)

  • 返回值:ClassName&(*this),也是引用,理由如上,并且可实现连续赋值(a=b=c)

  • 注意:

    ClassName class1;
    class1=class2;
    //该情况下,第一句调用无参的构造函数,第二句则调用了拷贝赋值运算符重载函数
    ClassName class1=class2;
    //用2给1赋值,调用了拷贝构造函数
    
  1. 流运算符的重载
  • 作用:重载对象的输入输出

  • 声明

    Class Test:id(4);
    istream& operator>> (istream& in,Test& dst){
        in>>dst.id;//id为Test类的对象dst的一个成员变量
        return in;//为了使得一个cin能输入多个数据,即cin>>a>>b;
    }
    ostream& operator<< (ostream& out,const Test& src);//同上
    
    • 函数名:operator>>和operator<<
    • 返回值:istream& 和 ostream& ,均为引用
    • 参数:流对象的引用,目标对象的常量引用。
  • 提示: 若在该类中,定义一个另外一个类定义的对象(ClassName C;)且另外一个类中未定义输入输出流,则可能会出现错误

  1. 函数运算符的重载
  • 声明:

    ReturnType operator()(Paramenters){//函数在声明时可以只写类型
        ...;
        return ElemType;
    }
    ClassName Obj;
    ElemType t=Obj(real_parameters);//Obj.operator()(real_parameters);
    
  • 作用:使得一个对象可以被直接调用,动态改变函数作用(例:一个比较大小的函数,可以利用这种方式,动态改变与哪个数作比较,从而得到结果)

  1. 下标运算符的重载
  • 声明:

    ReturnType operator[](Paramenters);
    
  • 若返回类型是引用,则可放等号左侧,即接受赋值(Obj[index]=value);若返回类型不是引用,则只可放括号右侧(value=Obj[index])

  • 作用:增强功能,使得以字符串等做下标也可能实现(类似stl中的map)

  1. 自增自减符的重载
  • 声明

    //前缀运算符的重载
    ReturnType operator++();
    ReturnType operator--();
    //后缀运算符的重载
    ReturnType operator++(int dummy);
    ReturnType operator--(int dummy);//dummy表示哑原文函数,为了区分前后函数,但无实质作用
    

成员函数 相关学习链接

  • 静态成员
  • 常成员

继承:在已有类的基础上产生新的类

  1. 继承
  • 常见继承方式:public,private

    • private

      class Derived:[private] Base{...};//缺省继承方式为private继承,[]表示里面内容可写可不写
      
    • public

      class Derived:public Base{...};
      
      • 基类(父类,base class):其中被继承的已有类
      • 派生类(子类,扩展类,derived class):继承得到的新类
      using Base::Base;//以此来继承基类构造函数
      
  • 注意:

    • 基类构造函数的默认值不会被派生类继承,但基类构造函数可以继承
    • 若基类的某构造函数被声明为私有成员函数,则派生类中无法声明与继承该构造函数
    • 若派生类使用了基类中的构造函数,则编译器不会再为派生类生成默认构造函数
  1. 函数重写:基类中已定义好的成员函数,在派生类中重新定义
  • 注意:若进行函数重写,则会屏蔽基类中其他同名的成员函数
  1. 虚函数
  • 向上映射:派生类对象转基类对象

    • 特点
      • 编译器可自动完成
      • 一种隐式自动类型转换
    • 凡是接受基类对象的地方(函数参数),可使用派生类对象,编译器会对派生类对象进行自动类型转换
  • 向下映射:基类对象转派生类对象

  • 多态 学习相关链接

    • 分类:静态多态、动态多态
      • 静态多态:一种在编译期间就会完成的,根据参数选择合适的函数
      • 动态多态:一种在程序运行时,根据基类的引用(指针)指向的对象来确定自己调用哪个类的虚函数
        • 条件
          1. 基类中包含虚函数,且派生类中一定要对积累虚函数进行重写
          2. 通过基类对象的指针或引用调用虚函数
  • 虚函数: 学习相关链接

    • 条件:参数是基类的引用且引用了虚函数

    • final

      • 作用:阻断某函数的继承

      • 格式

        ReturnType print() final;//后续子类均不可重写该函数
        
    • 纯虚函数

      • 在虚函数的形参列表后加上=0
      • 作用:只可作为声明做虚类
      • 包含该函数的类则称为抽象类(接口类),不可实例化

类型转换

  1. 自动类型转换:可隐式自动进行,不需人工干预 相关学习链接
  • 非自定义

    • 整型:

      int -> unsigned int -> long -> unsigned long -> long long ->unsigned long long
      
    • 浮点型

      float -> double
      
    • 其他情况

      1. 操作数中无浮点数

        当char、unsigned char、short、unsigned short出现在表达式,一般将其自动转为int,特殊情况下,unsigned short 也可能转换成 unsigned int。

      2. 橾作数中有浮点型数据

        所有操作数都将转换为 double 型。

      3. 赋值运算符两侧不对称

        将右值类型可能提升或降低为左值类型。

      4. 右值超出左值类型范围时

        结果无意义。

  • 自定义:只可对类进行操作,需借助转换构造函数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值