C++笔记 继承

1 继承
代码重用

class Human{
public:
    void say(){
        cout << "打招呼" << endl;
    }
};

//男人
class Man :public Human{

};
void main(){
    Man m;
    m.say();

    //1 父类类型的引用或指针
    Human* h_p = &m;
    h_p->say();

    Human &h1 = m;  //和Human h1 = m:不同的是 m和h1指向同一块内存
    system("pause");
}

继承的方式就是Man : public Human

打印结果

打招呼
打招呼

可见 Human的子类Man也可以调用父类的方法。

2 向父类构造方法传参

class Human{
public:
    Human(char *name,int age){
        this->name = name;
        this->age = age;
    }
    void say(){
        cout << "打招呼" << endl;
    }

protected:
    char *name;
    int age;
};

//==================男人
class Man : public Human {
public:
    Man(char *brother,char* s_name,int s_age,char *h_name,int h_age):Human(s_name,s_age),h(h_name,h_age){
        this->brother = brother;
    }

    void beFather(){
        cout << "当爸爸" << endl;
    }

private:
    char* brother;
    Human h;
};
void main(){
    Man m("Rose","DeBang",23,"James",31);

    system("pause");
}

可见,向父类构造方法传参,可以通过这中方式:

 Man(char *brother,char* s_name,int s_age,char *h_name,int h_age):Human(s_name,s_age),h(h_name,h_age)

第二个h表示给成员变量赋值

h(h_name,h_age)

3 父类与子类的构造函数和析构函数的调用顺序

class Hum a n {
public:
    Human(){
        cout << "Human 构造函数" << endl;
    }

    ~Human(){
        cout << "Huamn 析构函数" << endl;
    }
};

class Man :public Human{
public:
    Man(): Human(){
        cout << "Man 构造函数" << endl;
    }

    ~Man(){
        cout << "Man 析构函数" << endl;
    }

};

void func(){
    Man m;
}
void main(){
    func();
    system("pause");
}

打印结果:

Human 构造函数
Man 构造函数
Man 析构函数
Huamn 析构函数

由此可见,父类的构造函数先调用,子类的析构函数先调用。

4 子类调用父类的方法和属性

class Human{
public:
    void method(){
        cout << "Human 方法" << endl;
    }

    int age;

};

class Man:public Human{
public:
    void method(){
        cout << "Man 方法" << endl;
    }
};
void main(){
    Man m;

    //子类覆盖了和父类重名的方法  此方法将会执行子类中的方法
    m.method();

    //调用父类的方法
    m.Human::method();

    //访问父类的属性
    m.Human::age;

    system("pause");
}

打印结果

Man 方法
Human 方法

5 多继承

//人
class Human{

};

//动物
class Animal{

};

//学生 既是人 又是动物
class Student :public Human, public Animal{

};

6 继承的访问修饰

基类中      继承方式             子类中
publicpublic继承        public
publicprotected继承     protected
publicprivate继承       private

protectedpublic继承        protected
protectedprotected继承     protected
protectedprivate继承       private

privatepublic继承        子类无权访问
privateprotected继承     子类无权访问
privateprivate继承       子类无权访问

比如父类中的age是public修饰的,但是Man使用private继承。所以不能在main中访问Man的age属性

class Human{
public:
    int age;
};

class Man :private Human{

};

void main(){
    Man m;
    m.age;
}

报错:

7 继承的二义性
当A1和A2同时继承了A以后,B同时继承了A1和A2;那么此时B访问继承自A1和A2中的属性将会不明确。即:不知道B访问的是来自A1中的属性还是A2中的属性。如下:

class A{
public:
    char* name;
};

class A1 :public A{

};
class A2 :public A{

};

class B :public A1, public A2{

};
void main(){
    B b;
    b.name = "Green";
}

main函数中将会报错
这里写图片描述

添加virtual关键字后,将不再出现此问题

class A1 :virtual public A{

};
class A2 :virtual public A{

};
void main(){
    B b;
    b.name = "Green";
    //指定父类 显式调用
    b.A1::name;
}

virtual:虚继承,不同路径继承来的同名成员只有一份拷贝,解决不明确的问题。

8 纯虚函数
1 当 一个类有纯虚函数,这个类就是抽象类

//抽象形状
class Shape{
public:
    //纯虚函数
    virtual void Area()  =0;

    void print(){
        cout << "" << endl;
    }
};
//圆
class Circle{
public:
    Circle(int r){
        this->r = r;
    }
    void Area(){
        cout << "圆的面积" << 3.14*r*r << endl;
    } 
private:
    int r;
};
void main(){
    Circle c(10);
    c.Area();
    system("pause");
}

打印结果

圆的面积314

当圆中不实现Area方法时:

//圆
class Circle{
public:
    Circle(int r){
        this->r = r;
    }
private:
    int r;
};

main中调用Area()方法将会报错
这里写图片描述

2 所以子类继承,必须实现纯虚函数,如果没有实现,则子类也是抽象类。
3 抽象类不能实例化对象
这里写图片描述
9 接口
接口只是在逻辑上的划分,语法上和抽象类并没有区别

10 模板函数 当两个函数业务逻辑一样,只是参数的数据类型不一样时:

void myswap(int &a,int &b){
    int tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
}
void myswap(char&a,char &b){
    char tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
}

可以看到这两个函数都是把传来的值交换,只是第一个把两个int类型的值交换,第二个方法是把两个char类型的值交换。这是可以用模板函数:

template<typename T>
void myswap(T& a,T& b){
    T tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
}

模板函数和java中的反省如出一辙。

void main(){
    //根据实际类型,自动推导
    int a = 10, b = 20;
    myswap<int>(a,b); 
    cout << a << "," << b << endl;

    char x = 'x', y = 'y';
    myswap(x,y);
    cout << x << ','<<y << endl;

    system("pause");
}

打印结果

20,10
y,x
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值