基于C的C++学习day4

面向对象核心

1.继承(重点)

从基类(父类)基础上建立一个新的类。继承一些方法,体现了代码复用的思想

已经存在的类称为父类或基类

从父类或基类基础上新建的类称为派生类或子类

#include <iostream>

using namespace std;

class Father{
public:
    string first_name="王";
    void work(){
        cout<<"理发师"<<endl;
    }
};
class Son:public Father{
public:
    void work(){
        cout<<"程序员"<<endl;
    }
    void play(){
        cout<<"玩游戏"<<endl;
    }


};

int main()
{
    Son s;
    cout<<s.first_name<<endl;
    s.work();
    s.play();
}

上面派生类没有继承基类的带参的构造函数。因为如果不手动写构造函数

子类有一个默认无参的构造函数

父类有一个无参的构造函数

子类的无参构造函数中,会调用基类的无参构造函数

需要调用基类的代码来完成派生类中基类代码内存的开辟。 派生类的任意一个构造函数,都必须直接或者间接调用基类的任意一个构造函数

1.1透传构造

直接在派生类中的构造函数调用基类的构造函数

Son(string name)     ———》Father(name)

Son(string name,int age)---》Father(name,age)

#include <iostream>
using namespace std;
class Father{
private:
    string first_name;
    int age;
public:
    Father(string name){
        this->first_name=name;
    }
    Father(string name,int age){
        this->first_name=name;
        this->age=age;
    }
    void show(){
        cout<<first_name<<" "<<age;
    }

};
class Son:public Father{
public:
    Son(string name):Father(name){}
    Son(string name,int age):Father(name,age){}

};

int main()
{
    Son s("张三",18);
    s.show();

}

1.2委托构造

某个类中的构造函数调用这个类中的重载的构造函数

#include <iostream>
using namespace std;
class Father{
private:
    string first_name;
    int age;
public:
    Father(string name){
        cout<<"Father一个参数构造函数"<<endl;
        this->first_name=name;
    }
    Father(string name,int age){
        cout<<"Father两个参数构造函数"<<endl;
        this->first_name=name;
        this->age=age;
    }
    void show(){
        cout<<first_name<<" "<<age<<endl;
    }

};
class Son:public Father{
public:
    Son(string name):Son(name,18){}
    Son(string name,int age):Father(name,age){}

};

int main()
{
    Son s("张",20);
    s.show();
    Son s2("李");
    s2.show();
}

1.3对象的创建和销毁

#include <iostream>

using namespace std;

class Value{
private:
    string name;
public:
    Value(string name):name(name){
        cout<<name<<"创建了"<<endl;
    }
    ~Value(){
        cout<<name<<"销毁了"<<endl;
    }

};
class Father{
public:
    static Value s_value;
    Value value=Value("Father类的成员变量");
    Father(){
        cout<<"Father的构造函数"<<endl;
    }
    ~Father(){
        cout<<"Father的析构函数"<<endl;
    }

};
Value Father::s_value=Value("父类的静态Value");
class Son:public Father{
public:
    static Value s_value;
    Value value=Value("Son类的成员变量");
    Son(){
        cout<<"Son的构造函数"<<endl;
    }
    ~Son(){
        cout<<"Son的析构函数"<<endl;
    }


};
Value Son::s_value=Value("子类的静态Value");

int main()
{
    cout<<"main方法开始"<<endl;
    {
        Son s;
        cout<<"Son类对象使用中。。。"<<endl;

    }
    cout<<"main方法结束"<<endl;

}

过程

特点:

创建过程和销毁过程是对称的(先创建的后销毁,类似栈先进后出)

同样的内容,父类先创建,然后派生类。销毁的时候先派生类 后父类

静态成员最先创建,最后销毁

继承 提高开发效率 但是会稍微降低运行效率

1.4多重继承

一个派生类它有多个基类,会从多个基类中继承方法

#include <iostream>

using namespace std;
class Sofa{
public:
    void sit(){
        cout<<"可以坐着";
    }
};
class Bed{
public:
    void lay(){
        cout<<"可以躺着"<<endl;
    }
};
class SofaBed:public Sofa,public Bed{

};
int main()
{
    SofaBed s;
    s.sit();
    s.lay();
}

Car driver()

House sleep()nn

房车继承Car 和House

1.5多重继承的二义性问题

当多个基类中有同名的成员。此时就会产生二义性

可以通过类名::方法来区分

#include <iostream>

using namespace std;
class Sofa{
public:
    void sit(){
        cout<<"可以坐着"<<endl;
    }
    void position(){
        cout<<"放在客厅";
    }

};
class Bed{
public:
    void lay(){
        cout<<"可以躺着"<<endl;
    }
    void position(){
        cout<<"放在卧室";
    }
};
class SofaBed:public Sofa,public Bed{

};

int main()
{
    SofaBed s;
    s.sit();
    s.lay();
    s.Sofa::position();//沙发的位置
    s.Bed::position();//床的位置

}

2.权限 (重要)

private 本类中可以访问 在子类中不可以访问 全局中不可以访问

protected 本类中可以访问 在子类中可以访问 全局中不可以访问

public 本类中可以访问 在子类中可以访问 全局中也可以访问

不同权限的继承

不管哪种继承方式,基类中私有的成员属性。都是不能直接访问

public继承

        public继承之后 成员在原来基类是什么权限,在派生类中还是什么权限

#include <iostream>
using namespace std;
class Father{
public:
    string str1="public";
protected:
    string str2="protected";
private:
    string str3="private";

};
class Son:public Father{
public:
    void show(){
        cout<<str1<<endl;
        cout<<str2<<endl;
        //cout<<str3<<endl;父类私有不能访问
    }

};
int main()
{
    Son s;
    s.show();
}

protectd继承

        protect继承之后。所有继承过来成员都会在Son中变成protected

#include <iostream>
using namespace std;
class Father{
public:
    string str1="public";
protected:
    string str2="protected";
private:
    string str3="private";

};
class Son:protected Father{
public:
    void show(){
        cout<<str1<<endl;
        cout<<str2<<endl;
        //cout<<str3<<endl;父类私有不能访问

    }

};
class GrandSon:public Son{
public:
    void show(){
        cout<<str1<<endl;
        cout<<str2<<endl;
        //cout<<str3<<endl;父类私有不能访问

    }


};
int main()
{
   Father f;
   cout<<f.str1<<endl;

   Son s;
   cout<<s.str1<<endl;  //在子类中变成了protected类型,在全局中不能访问
}

private继承

        派生类私有继承之后 属性在派生中都变成私有.也就是下方的Son类中的属性都变成私有

#include <iostream>
using namespace std;
class Father{
public:
    string str1="public";
protected:
    string str2="protected";
private:
    string str3="private";

};
class Son:private Father{
public:
    void show(){
        cout<<str1<<endl;
        cout<<str2<<endl;
        //cout<<str3<<endl;父类私有不能访问
    }

};
class GrandSon:public Son{
public:
    void show(){
//        cout<<str1<<endl; //因为子类中变成私有 孙子类全访问不到
//        cout<<str2<<endl;
    }

};
int main()
{

   Son s;
   s.show();

   GrandSon gs;
   gs.show();

}

3.多态(重要)

函数重载是静态多态 编译的时候就已经确定

多态就是多种状态,可以一个接口实现多种状态。根据传入对象的不同,虽然调用同样接口,但 选择不同的代码实现。

多态需要三种条件:

  1. pubic继承
  2. 派生类覆盖基类中的函数
  3. 接口参数为基类对象的指针或者基类引,指向派生对象

virtual关键字修饰的函数就是虚函数

  1. 当函数覆盖成功后,虚函数具有传递性。默认的函数都有virtual关键字
  2. 成员函数和析构函数可以定义为虚函数。静态函数和构造函数不可以
  3. 如果声明和定义分离时,virtual关键字只需要加在声明处。

3.1没有使用多态的情况

这时指针是哪个对象定义的, 就调用哪个对象类型中的方法。如下方Animal * ,就会Aniaml类中的方法

#include <iostream>
using namespace std;
class Animal{
public:
    void eat(){
        cout<<"吃东西"<<endl;
    }
};
class Dog:public Animal{
public:
    void eat(){
        cout<<"吃狗粮"<<endl;
    }
};
class Cat:public Animal{
public:
    void eat(){
        cout<<"吃鱼"<<endl;
    }
};
int main()
{
    Dog d;
    d.eat();  //吃狗粮

    Animal * a=&d; //静态的
    a->eat();  //吃东西

    Cat c;
    Animal * b=&c;
    b->eat(); //吃东西
}

3.2多态的实现

覆盖的函数后面加override 关键字。如果没有发生重写就会报错

#include <iostream>
using namespace std;
class Animal{
public:
    virtual void eat(){
        cout<<"吃东西"<<endl;
    }
};
class Dog:public Animal{
public:
    void eat() override
{
        cout<<"吃狗粮"<<endl;
    }
};
class Cat:public Animal{
public:
    void eat() override
{
        cout<<"吃鱼"<<endl;
    }
};
int main()
{
    Dog d;
    d.eat();  //吃狗粮
    Animal * a=&d;
    a->eat();  //吃东西
    Cat c;
    Animal * b=&c;
    b->eat(); //吃东西
}

3.3多态应用

接口使用多态

#include <iostream>
using namespace std;
class Animal{
public:
    virtual void eat(){
        cout<<"吃东西"<<endl;
    }
};
class Dog:public Animal{
public:
    void eat(){
        cout<<"吃狗粮"<<endl;
    }
};
class Cat:public Animal{
public:
    void eat(){
        cout<<"吃鱼"<<endl;
    }
};
void test1(Animal * a){
    a->eat();
}
void test2( Animal &b){
    b.eat();
}
int main()
{
    //接口调用
    Cat c2;
    test2(c2);
    test1(&c2);
}

基类指针或者基类引用(隐含继承)调用虚函数的时候,就是多态。触发查虚函数表

原理:

每一个有虚函数的类都有虚函数表

3.4多态可能出现的问题:

#include <iostream>
using namespace std;
class Animal{
public:
    virtual void eat(){
        cout<<"吃东西"<<endl;
    }
     ~Animal(){
        cout<<"Animal的析构函数"<<endl;
    }
};
class Dog:public Animal{
public:
    void eat(){
        cout<<"吃狗粮"<<endl;
    }
    ~Dog(){
        cout<<"Dog类的析构函数"<<endl;
    }
};

int main()
{
    Animal * a=new Dog;
    delete a; //只会调用Animal的析构函数
}

错误原因:

析构函数没有进行覆盖。实际析构函数也没法覆盖。但是可以把析构函数定义为虚函数

#include <iostream>
using namespace std;
class Animal{
public:
    virtual void eat(){
        cout<<"吃东西"<<endl;
    }
    virtual ~Animal(){
        cout<<"Animal的析构函数"<<endl;
    }
};
class Dog:public Animal{
public:
    void eat(){
        cout<<"吃狗粮"<<endl;
    }
    ~Dog(){
        cout<<"Dog类的析构函数"<<endl;
    }
};
int main()
{
//    Dog * d=new Dog;
//    delete d;
    Animal * a=new Dog;
    delete a;

}

4.抽象类(掌握)

抽象的概念。只有一些说明,没有具体实现,相当于一个框架的作用。抽象类中不具体的创建对象,不能作为参数类和和返回值类型

一个类中有纯虚函数,这个类就是抽象类;

如果一个类是抽象类,那么一定会有纯虚函数

如果继承了抽象类,需要实现全部实现,才能创建对象。否则它也会成为抽象

#include <iostream>
using namespace std;
class Shape{
public:
    virtual void area()=0;
    virtual void perimeter()=0; //面积
};
class Rectangle:public Shape{
public:
    void area(){
        cout<<"长方形面积"<<endl;
    }
    void perimeter(){
        cout<<"长方形的周长"<<endl;
    }
};
int main()
{
    Rectangle r;
    r.area();
    r.perimeter();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值