JHHK

欢迎来到我的个人网站
行者常至 为者常成

9、初始化列表、多态

目录

初始化列表

特点
一种便捷的初始化成员变量的方式
只能用在构造函数中
初始化顺序只跟成员变量的声明顺序有关

一、下面的2种写法是等价的

struct Person{
    int _age;
    int _height;

    Person(int age,int height){
        this->_age = age;
        this->_height = height;
        cout<<"this->age is "<<this->_age<<endl;
        cout<<"this->height is "<<this->_height<<endl;
    }
};

初始化列表只能在构造函数中

struct Person{
    int _age;
    int _height;

    Person(int age,int height):_age(age),_height(height){

        cout<<"this->age is "<<this->_age<<endl;
        cout<<"this->height is "<<this->_height<<endl;
    }
};

二、构造函数的互相调用

注意:下面的写法是错误的,初始化的是一个临时对象

struct Person{
    int _age;
    int _height;

    Person(){
        cout<<"this is11 "<<this<<endl;
        //初始化的是一个临时对象
        Person(0,0);
    }

    Person(int age,int height):_age(age),_height(height){
        cout<<"this is "<<this<<endl;
        cout<<"this->age is "<<this->_age<<endl;
        cout<<"this->height is "<<this->_height<<endl;
    }
};
struct Person{
    int _age;
    int _height;

    //构造函数的调用
    Person():Person(0,0){ }

    //初始化列表的使用
    Person(int age,int height):_age(age),_height(height){ }
};

三、初始化列表与默认参数配合使用

struct Person{
    int _age;
    int _height;

//    Person(){}
//    Person(int age):Person(age,0){}

    Person(int age = 0,int height= 0):_age(age),_height(height){

    }
};

如果函数声明和实现是分离的
初始化列表只能写在函数的实现中
默认参数只能写在函数的声明中

struct Person{
    int _age;
    int _height;
    
    // 默认参数只能写在函数的声明中
    Person(int age = 0,int height=0);
};

// 构造函数的初始化列表只能写在实现中
Person::Person(int age,int height):_age(age),_height(height){
    
}

父类的构造函数

子类的构造函数默认会调用父类的无参构造函数
如果子类的构造函数显式地调用了父类的有参构造函数,就不会再去默认调用父类的无参构造函数
如果父类缺少无参构造函数,子类的构造函数必须显式调用父类的有参构造函数

class Animal{
    int _age;
public:
    int getAge(){
        return _age;
    }
    
    Animal(){
        cout<<"Animal"<<endl;
    }
    
    Animal(int age):_age(age){
        cout<<" Animal(int age)"<<endl;
    }
    
    ~Animal(){
        cout<<"~Animal()"<<endl;
    }
};

class Cat:public Animal{
    int _life;
public:
    Cat(int age=0,int life=0):Animal(age),_life(life){
        //父类的构造函数相当于在此调用
        cout<<" Cat(int age=0,int life=0)"<<endl;
    }
    
    ~Cat(){
        cout<<"~Cat()"<<endl;
        //父类的析构函数相当于在此调用
    }
};

void inheritUsing(){
    Cat c;
}

构造函数与析构函数的调用顺序
Animal(int age)
Cat(int age=0,int life=0)
~Cat()
~Animal()

父类指针与子类指针

父类指针可以指向子类对象,是安全的,开发中经常用到(继承方式必须是public)

子类指针指向父类对象是不安全的

子类指针访问的范围会超出父类对象,会出现内存非法访问

void fatherAndSubClassUsing(){
    Animal * an = new Animal();
    
    //父类指针可以指向子类对象
    Animal *an1 = new Cat();
    
    //反之不可以
    //Cat * ca = new Animal();
}

多态

默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态

多态是面向对象非常重要的一个特性
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
在运行时,可以识别出真正的对象类型,调用对应子类中的函数

多态的要素
子类重写父类的成员函数(override)
父类指针指向子类对象
利用父类指针调用重写的成员函数

class Transport{
public:
//    void run(){
//        cout<<"Transport run"<<endl;
//    };
//
//    void stop(){
//         cout<<"Transport stop"<<endl;
//    };
    
    /**
    virtual虚函数
    没有virtual修饰,子类不会调用重写的方法,而是会调用父类方法
    需要有virtual修饰,子类重写后就会调用子类的方法
    */
    virtual void run(){
        cout<<"Transport run"<<endl;
    };
    
    virtual void stop(){
         cout<<"Transport stop"<<endl;
    };
};

class Truck:public Transport{
public:
    void run(){
        cout<<"Truck run"<<endl;
    };
    
    void stop(){
         cout<<"Truck stop"<<endl;
    };
};

class Car:public Transport{
public:
    void run(){
        cout<<"Car run"<<endl;
    };
    
    void stop(){
         cout<<"Car stop"<<endl;
    };
};


void paoAndTing(Transport * tran){
    tran->run();
    tran->stop();
}


void nineDayFunc(){
    Transport * tran = new Transport();
    Truck * truc = new Truck();
    Car * ca = new Car();

    //没有虚函数调用以左侧为准,有虚函数调用以右侧为准
    paoAndTing(truc);
    paoAndTing(ca);
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.