C++基础 | 继承和派生

耦合度,高内聚,低耦合
程序设计追求高内聚,低耦合
高内聚指一个函数干的事情极少,甚至只干一件事情
低耦合是类之间的关系越少越好

继承

继承的耦合度很高,但是方便不用写太多代码

在 C++中可重用性(software reusability)是通过继承(inheritance)这一机制来 实现的。

定义:
类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类 的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。
派生与继承,是同一种意义两种称谓。

#include <iostream>
using namespace std;
class Student
{
public:
    void dis() {
        cout<<name<<endl;
        cout<<age<<endl;
}
      string name;
      int age; 
};

class Student2:public Student
{
public:
    Student2(string n,int a,char s,float f)
    {
        name = n; age = a; sex = s; score = f;
    }
    void dis() {
        Student::dis();
        cout<<sex<<endl;
        cout<<score<<endl;
    }
     char sex;
     float score;
};

派生类的组成
派生类中的成员,包含两大部分,一类是从基类继承过来的,一类是自己增加 的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。


20988794-5f4f930f1c10d98d.png
屏幕快照 2020-02-02 下午8.26.13.png

几点说明: 1,全盘接收,除了构造器与析构器。基类有可能会造成派生类的成员冗余,所以 说基类是需设计的。
2,派生类有了自己的个性,使派生类有了意义。

派生类的构造函数是一定会调用基类的构造函数的,一般都是将继承过来的变量用初始化列表来初始化。如果不想写初始化列表的话,基类要有无参构造函数。

一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个 基类, 称为单继承。

继承的方式

语法:
class 派 类名:[继承 式] 基类名 {
派 类成员声明;
};

public公有继承:
当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生
类中 不变,而基类的私有成员不可访问。

protected保护继承:
保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生
类 中,而基类的私有成员不可访问。

private私有继承:
当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成
员身 份出现在派生类中,而基类的私有成员在派生类中不可访问。

private成员在子类中依然存在,但是却无法访问到。不论何种方式继承 基类,派生类都不能直接使用基类的私有成员 。

#include <iostream>
using namespace std;
class A
{
private:
    int a;
protected:
    int b;
public:
    int c;
    A() {
        a = 0;
        b = 0;
        c = 0; 
    }
    void set(int a, int b, int c)
    {
        this->a = a;
        this->b = b;
        this->c = c;
    } 
};
class B : public A
{
public:
    void print()
    {
        cout<<"a ="<<a<<endl;  //不能访问,a是基类的private
        cout<<"b ="<<b<<endl;
        cout<<"c ="<<c<<endl;
    } 
};
class C : protected A
{
public:
    void print()
    {
        cout<<"a ="<<a<<endl;   //不能访问,a是基类的private
        cout<<"b ="<<b<<endl;
        cout<<"c ="<<c<<endl;
    } 
};
class D : private A
{
public:
void print()
{
cout<<"a = "<<a<<endl;  //不能访问,a是基类的private
cout<<"b = "<<b<<endl; 
cout<<"c = "<<c<<endl; 
} };
int main(void)
{
    A aa;
    B bb;
    C cc;
    D dd;
    aa.c = 100;
    bb.c = 100;
    cc.c = 100;
    dd.c = 100;

    aa.set(1, 2, 3); 
    bb.set(10, 20, 30); 
    cc.set(40, 50, 60); //不能访问,set是protected成员
    dd.set(70, 80, 90); //不能访问,set是private成员
    bb.print(); 
    cc.print(); 
    dd.print(); 
    return 0; 
}
类型兼容性原则

类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类 的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之 外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能 解决的问题,公有派生类都可以解决。

类型兼容规则中所指的替代包括以下情况:
子类对象可以当作父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象

在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。
子类就是特殊的父类 (base *p = &child;)

#include <iostream>
using namespace std;
class Parent
{
public:
    void printP()
    {
        cout << "parent...." << endl;
    }
};
class Child : public Parent
{
    public:
        void printC()
        {
            cout << "child..." << endl;
        } 
};
void print01(Parent  *p)
{
    p->printP();
}
void print02(Parent  &p)
{
    p.printP();
}
int main() {
    /*
    //Parent p;
    //Child c=p;    //p对象填充不满c对象空间

    Child c;
    Parent p=c; //c对象所占用的内存空间>=p对象占用空间,能够填充满p对象所需要空间
    */

    Child c1;
    c1.printC();
    Parent *p = NULL; //可以用父类指针指向子类对象 
    p = &c1;
    p->printP();    //执行父类的函数
    Child   c2;
    Parent  p2;
    print01(&p2);
    print01(&c2); // 父类指针指向子类对象
    print02(p2);
    print02(c2); // 父类引用指向子类对象
    //第二层含义   用子类初始化父类对象 
    Child c3;
    Parent p3 = c3;
return 0;
}
继承中的构造和析构

在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化.
在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理.

继承中构造析构调用原则:
1、子类对象在创建时会首先调用父类的构造函数
2、父类构造函数执行结束后,执行子类的构造函数
3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
4、析构函数调用的先后顺序与构造函数相反

先构造父类,再构造成员变量、最后构造自己
先析构自己,在析构成员变量、最后析构父类

#include <iostream>
using namespace std;
class Object
{
public:
    Object(const char* s)
    {
        cout<<"Object()"<<" "<<s<<endl;
    }
~Object() {
        cout<<"~Object()"<<endl;
    }
};
class Parent : public Object
{
public:
    Parent(const char* s) : Object(s)
    {
        cout<<"Parent()"<<" "<<s<<endl;
    }
~Parent() {
        cout<<"~Parent()"<<endl;
    }
};
class Child : public Parent
{
public:
    Child() : o2("o2"), o1("o1"), Parent("Parameter from Child!")
    {
        cout<<"Child()"<<endl;
    }
~Child() {
        cout<<"~Child()"<<endl;
    }
    private:
    Object o1;
Object o2; };
void run() {
    Child child;
}
int main(int argc, char *argv[])
{
run();
return 0;
}


运行结果:
Object() Parameter from Child!
Parent() Parameter from Child!
Object() o1
Object() o2
Child()
~Child()
~Object()
~Object()
~Parent()
~Object()
继承中同名成员变量处理方法

1、当子类成员变量与父类成员变量同名时
2、子类依然从父类继承同名成员
3、在子类中通过作用域分辨符::进行同名成员区分(在派生类中使用基
类的同名成员,显式地使用类名限定符)
4、同名成员存储在内存中的不同位置

派生类中的static关键字

1.基类定义的静态成员,将被所有派生类共享

  1. 根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具 有不同的访问性质 (遵守派生类的访问控制)
    3.派生类中访问静态成员,用以下形式显式说明:
    类名 :: 成员
    或通过对象访问:对象名 . 成员

多继承与虚继承

多继承

class C:public c1, public c2 {}

虚继承virtual

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性

如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象

要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。

虚继承声明使用关键字 virtual

如:class B1: virtual public B { }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值