07.C++继承和多态

(创建于2017/12/25)

1.继承的形式

#include <iostream>

//继承
//代码的重用性
using namespace std;


//人类
class Human{
public:
    void say(){
        cout << "说话" << endl;
    }
protected:
    char* name;
    int age;
};

//男人
class Man : public Human{
public:
    //泡妞
    void chasing(){
        cout << "泡妞" << endl;       
    }
private:
    //兄弟
    char* brother;
};

void work(Human& h){
    h.say();
}

void main(){
    Man m1;
    m1.say();

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

    Human &h1 = m1;
    h1.say();

    //子类对象初始化父类类型的对象
    Human h2 = m1;

    system("pause");
}


输出结果:
说话
说话
说话
请按任意键继续. . .

2.向父类构造方法传参

#include <iostream>

//继承
//代码的重用性
using namespace std;

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 chasing(){
        cout << "泡妞" << endl;
    }
private:
    //兄弟
    char* brother;
    Human h;
};

void main(){
    Man m1("danny","jack",18,"jason",18);

    system("pause");
}

3.构造函数与析构函数调用的顺序

#include <iostream>

//继承
//代码的重用性
using namespace std;

class Human{
public:
    Human(char* name, int age){
        this->name = name;
        this->age = age;
        cout << "Human 构造函数" << endl;
    }
    ~Human(){
        cout << "Human 析构函数" << endl;
    }
    void say(){
        cout << "说话" << endl;
    }
protected:
    char* name;
    int age;
};

//男人
class Man : public Human{
public:
    //给父类构造函数传参
    Man(char *brother, char *s_name,int s_age) : Human(s_name, s_age){
        this->brother = brother;
        cout << "Man 构造函数" << endl;
    }
    ~Man(){
        cout << "Man 析构函数" << endl;
    }
    //泡妞
    void chasing(){
        cout << "泡妞" << endl;
    }
private:
    //兄弟
    char* brother;  
};

void func(){
    //父类构造函数先调用
    //子类的析构函数先调用
    Man m1("danny", "jack", 18);
}

void main(){
    func();

    system("pause");
}

输出结果:
Human 构造函数
Man 构造函数
Man 析构函数
Human 析构函数
请按任意键继续. . .

4.子类对象调用父类的成员

#include <iostream>

//继承
//代码的重用性
using namespace std;

class Human {
public:
    Human(char* name, int age) {
        this->name = name;
        this->age = age;
        cout << "Human 构造函数" << endl;
    }
    ~Human() {
        cout << "Human 析构函数" << endl;
    }
    void say() {
        cout << "说话" << endl;
    }
public:
    char* name;
    int age;
};

//男人
class Man : public Human {
public:
    //给父类构造函数传参
    Man(char *brother, char *s_name, int s_age) : Human(s_name, s_age) {
        this->brother = brother;
        cout << "Man 构造函数" << endl;
    }
    ~Man() {
        cout << "Man 析构函数" << endl;
    }
    //泡妞
    void chasing() {
        cout << "泡妞" << endl;
    }
    void say() {
        cout << "男人喜欢装逼" << endl;
    }
private:
    //兄弟
    char* brother;
};

void main() {
    //是覆盖,并非多态
    Man m1("alan", "john", 18);
    //调用子类的方法
    m1.say();
    //调用父类的方法
    m1.Human::say();
    //调用父类的方法
    Human h = m1;
    h.say();
    //修改父类属性值
    m1.Human::age = 10;

    system("pause");
}

5.多继承

#include <iostream>

//继承
//代码的重用性
using namespace std;
class Person{

};

//公民
class Citizen{

};

//学生,既是人,又是公民
class Student : public Person, public Citizen{

};

6.继承的访问修饰

#include <iostream>

//继承
//代码的重用性
using namespace std;

//继承的访问修饰
//基类中      继承方式             子类中
//public     & public继承 = > public
//public     & protected继承 = > protected
//public     & private继承 = > private
//
//protected  & public继承 = > protected
//protected  & protected继承 = > protected
//protected  & private继承 = > private
//
//private    & public继承 = > 子类无权访问
//private    & protected继承 = > 子类无权访问
//private    & private继承 = > 子类无权访问
//人类

class Human{
public:
    void say(){
        cout << "说话" << endl;
    }
private:
    char* name;
    int age;
};

//男人
class Man : protected Human{
public:
    //泡妞
    void chasing(){
        cout << "泡妞" << endl;       
    }
private:
    //兄弟
    char* brother;
};

7.继承的二义性,指的是A和B同时继承了C,C中有name属性,那么A和B都有了自己的name属性,此时D同时继承了A和B,那么D中的name属性究竟使用哪个?

#include <iostream>

//继承
//代码的重用性
using namespace std;

class A{
public:
    char* name;
};
//虚函数(virtual function),虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。

//如果没有这个virtual关键字,b.name = "aaa";会报错,因为name属性不明确
class A1 : virtual public A{
    
};

class A2 : virtual public A{

};

class B : public A1, public A2{

};

void main(){
    B b;    
    b.name = "aaa";
    //指定父类显示调用
    b.A1::name = "bbb";
    b.A2::name = "ccc";
    
    cout << b.name << endl;
    cout << b.A1::name << endl;
    cout << b.A2::name << endl;
    system("pause");
}

//使用了virtual关键字,使得调用的name属性是子类重写后的属性,也就是调用的子类的,
//几次赋值相当于都是给b中的name重新赋值,所以打印结果如下
输出结果:
ccc
ccc
ccc
请按任意键继续. . .

8.虚函数

//多态(程序的扩展性)
//动态多态:程序运行过程中,觉得哪一个函数被调用(重写)
//静态多态:重载

//发生动态的条件:
//1.继承
//2.父类的引用或者指针指向子类的对象
//3.函数的重写

#include "Plane.h"
#include "Jet.h"
#include "Copter.h"
//业务函数
void bizPlay(Plane& p){
    p.fly();
    p.land();
}

void main(){
    Plane p1;
    bizPlay(p1);

    //直升飞机
    Jet p2;
    bizPlay(p2);

    Copter p3;
    bizPlay(p3);

    system("pause");
}

Jet.h

#pragma once

#include "Plane.h"

//直升飞机
class Jet : public Plane{
    virtual void fly();
    virtual void land();
};

Jet.cpp

#include "Jet.h"
#include <iostream>
using namespace std;

void Jet::fly(){
    cout << "直升飞机在原地起飞..." << endl;
}

void Jet::land(){
    cout << "直升飞机降落在女神的屋顶..." << endl;
}

Plane.h

#pragma once

//普通飞机
class Plane{
public:
    virtual void fly();
    virtual void land();
};

Plane.cpp

#include "Plane.h"

#include <iostream>
using namespace std;

void Plane::fly(){
    cout << "起飞" << endl;
}

void Plane::land(){
    cout << "着陆" << endl;
}

Copter.h

#pragma once

#include "Plane.h"

//普通飞机
class Copter : public Plane{
public:
    virtual void fly();
    virtual void land();
};

Copter.cpp

#include "Copter.h"
#include <iostream>
using namespace std;

void Copter::fly(){
    cout << "喷气式飞机在跑道上起飞..." << endl;
}

void Copter::land(){
    cout << "喷气式飞机在跑道上降落..." << endl;
}

9.纯虚函数(抽象类)

//1.当一个类具有一个纯虚函数,这个类就是抽象类
//2.抽象类不能实例化对象
//3.子类继承抽象类,必须要实现纯虚函数,如果没有,子类也是抽象类
//抽象类的作用:为了继承约束,根本不知道未来的实现
//形状

class Shape{
public:
    //纯虚函数
    virtual void sayArea() = 0;
    void print(){
        cout << "hi" << endl;
    }
};

//圆
class Circle : public Shape{
public:
    Circle(int r){
        this->r = r;
    }
    void sayArea(){
        cout << "圆的面积:" << (3.14 * r * r) << endl;
    }
private:
    int r;
};

void main(){
    //Shape s;
    Circle c(10);

    system("pause");
}

10.接口(只是逻辑上的划分,语法上跟抽象类的写法没有区别)

//可以当做一个接口
class Drawble{
    virtual void draw();
};

11.模板函数(泛型)

/*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;
}
*/

//发现:这两个函数业务逻辑一样,数据类型不一样
template <typename T>
void myswap(T& a, T& b){
    T tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
}

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

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

    system("pause");
}


12.多继承,虚继承,二义性
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中声明的名字进行访问时,可能产生二义性,如果再多继承路径上有一个公共的基类,那么再继承路径的汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象,要使这个公共 基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,是这个基类成为虚基类

#include <stdio.h>
#include<stdlib.h>
class C {
public:
    int c;
};
class Base1 :virtual public C{
public:
    int b1;
    Base1(int b1) {
        this->b1 = b1;
        printf("b1=%d\n", b1);
    }
};

class Base2 :virtual public C{

public:
    int b2;
    Base2(int b2) {
        this->b2 = b2;
        printf("b2=%d\n", b2);
    }
};

class B :public Base1, public Base2 {

public:
    int b;
    B(int b1, int b2, int b) :Base1(b1), Base2(b2) {

        this->b = b;
        printf("b=%d\n", b);
    }
};

void main() {

    printf("hello\n");
    B b(1, 2, 3);
    b.c;
    system("pause");
}

不适用virtual导致
严重性 代码  说明  项目  文件  行   禁止显示状态
错误  C2385   对“c”的访问不明确  Project10   c:\users\renzhenming\documents\visual studio 2015\projects\project10\project10\1.cpp    41  

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容