面向对象之继承

本文详细介绍了C++中的类继承概念,包括单继承、多继承和派生类的构造与析构函数。通过Base基类和Drived派生类的实例展示了如何创建和使用派生类,并解释了虚函数、构造函数和析构函数的重要性。此外,还给出了Person基类及其man和woman派生类的示例,说明了多态性和对象的生命周期。
摘要由CSDN通过智能技术生成

内容

  1. 在c++里,一个类(派生类)可以从另一个类(继承类)中继承。继承是一种复用代码的机制。每个派生类都继承其基类数据成员和成员函数,派生类只需要编写与基类行为不同或者扩展方面(继承改写–用虚函数,新加行为方法);
  2. 一个派生类可以从一个基类派生(单继承),也可以从多个基类派生(多继承)。
  3. 派生类的定义格式:
    class<派生类名>:<继承方式><基类名>{
    <派生类新定义成员>
    };

    其中:
    class是关键词
    <派生类名>是新定义的一个类的名字,是从<基类名>中按照指定的<继承方式>派生出来的。
    <继承方式>:
    public—公有基类
    private—私有基类
    protected—保护基类

简单的继承实例

Base基类

#include<iostream>
using namespace std;

class Base {
private:
	int m_bnumber;
public:
	//构造函数生成对象
	Base() {//默认构造函数
		m_bnumber = 0;
		cout << "Base() called "<<endl;
	}
	Base(int i):m_bnumber(i) //初始化列表效率高与下面的(相当于把m_bnumber赋值为i)
	{//普通构造函数
		//m_bnumber = i;有初始化列表就不用这个语句了
		cout << "Base(i) called "<<endl;
	}
	//基类的析构函数,必须是virtual的,
	//否则,我们再释放一个指向派生类的对象的时候
	//就不会调用派生类中的析构函数了
	//就只会调用基类中的析构函数了
	 virtual ~Base() {
		cout << "~Base() called "<<endl;
	}
	//行为
public:
	int getnumber() {
		return m_bnumber;
	}
	virtual void print() {//后续要改写,加virtual
		cout << m_bnumber << endl;
	}
};

Drived派生类

class Drived :public Base {
private:
	int m_dnumber;
public:
	//默认构造
	Drived():Base(),m_dnumber(0)//初始化列表(首先调用基类的构造函数对基类初始化,再对自己的数据成员初始化)
	{
		cout << "Drived() called " << endl;
	}
	//普通构造
	Drived(int x, int y):Base(x),m_dnumber(y) {//使用初始化列表效率更高
		//Base(x);
		//m_dnumber = y;
		cout << "Drived(int x, int y) called " << endl;
	}
	//析构函数
	~Drived() {//若有一个新的类继承Derived类,则这个析构需要加上virtual
		cout << "~Drived() called " << endl;
	}
public:
	//改写
	void print() {
		Base::print();//调用基类中的print,打印m_bnumber
		cout << m_dnumber<<endl;
	}
	//新添加方法或者成员函数
	void hello() {
		cout << "hello world!" << endl;
	}
};

main主函数

int main() {
	Drived d(1,7);//从栈上生成Drived实例对象
	//先调用基类的构造函数,再调用派生类的构造函数
	cout<<d.getnumber()<<endl;//从派生类中调用基类中的getnumber//1
	d.print();//1 7
	d.hello();

	Drived* p = new Drived(2,8);//从堆上分配了个对象
	cout<<p->getnumber()<<endl;
	p->print();
	p->hello();
	delete p;//将p释放
	//p析构,先调用派生类的析构函数,再调用基类的析构函数

	
	//可以用派生类赋值给基类
	Base* p2 = new Drived(3,9);//基类指针指向派生类对象
	cout<<p2->getnumber()<<endl;
	
	p2->print();//执行的是派生类中的print();因为在基类中这个函数为虚函数,所以即使指针是基类,但是它指向的是派生类,就调用派生类
				//若不加virtual则调用基类
	//p2->hello();hello不是基类中的对象
	delete p2;
	//解释为什么基类中的析构函数为什么是virtual
	//p2析构先调用指向的派生类的析构函数,再调用基类的析构函数
	//不加virtual,就不会调用派生类中的析构函数,那么派生类中的某些资源可能就会泄露

	//最后对象d析构
	return 0;
}

结果展示

在这里插入图片描述

注意

  1. 初始化列表
  2. 派生类继承了基类的数据和函数方法;
  3. 派生类可以自己定义新的方法和数据成员;
  4. 派生类中要改写(override)基类中的虚函数(带virtual关键字的函数),不能改写非虚函数;
  5. 基类中的 析构函数设为虚函数virtual,否则再释放对象时,可能造成派生类中资源泄露;
  6. 构造析构函数调用顺序:基类中的构造函数–>派生类中的构造函数–>派生类中的析构函数–>基类中的析构函数;

DEMO

基类-人:构造 ,析构,
eat(),getname(),ishealthy();
派生类-男人:构造,析构,eat(),smoke()
派生类-女人:构造,析构,eat(),buy()

基类person

#include <iostream>
using namespace std;

class Person {
public://构造函数
         Person() { //默认构造函数
             m_name = new char[1];
             *m_name = '\0';
             m_age = 0;
             m_sex = 'M';
             m_height = 0.0f;
             m_weight = 0.0f;
             cout << "Person() called " <<m_name << endl;
         };
         Person(const char* name, int age, char sex, float height, float weight);//普通构造函数
         virtual  ~Person(){//析构函数加virtual
             cout << "~person called "<<m_name<<endl;
         }
public://工具函数
    char* getname() {
        return m_name;
    }
    void setname(char *name) {
        if (name == NULL) {
            m_name = new char[1];
            *m_name = '\0';
        }
        else {
            m_name = new char[strlen(name)+1];
            strcpy_s(m_name, strlen(name) + 1,name);
        }
    } 
 private://数据成员
         char *m_name;
         int m_age;
         char m_sex;
         float m_height;
         float m_weight;
public://行为
   virtual void eat() {//加virtual
        cout <<m_name<< " is eating!!!" << endl;
    }
    bool ishealth() {
        float bmi = m_weight / (m_height*m_height);
        return bmi <= 25.0f && bmi >= 20.0f;
    }
};
Person::Person(const char* name, int age, char sex, float height, float weight) {
    m_name = new char[strlen(name)+1];
    strcpy_s(m_name, strlen(name) + 1,name);
    m_age = age;
    m_sex = sex;
    m_height = height;
    m_weight = weight;
    cout << "Person(char* name, int age, char sex, float height, float weight) called " << m_name << endl;
}

man派生类

class man :public Person {
private:
    int m_house;//房数
public:
    man() :Person() {//默认构造
        cout << "man() :Person() called " << endl;
    }
    man(const char* name, int age, float height, float weight, int num) :Person(name,
        age, 'M', height, weight), m_house(num) {//普通股构造函数
        cout << "man(const char* name, int age, float height, float weight,int num) called" << endl;
    }
    ~man() {//析构函数
        cout << "~man() called " << endl;
    }
public:
    //行为
    void eat() {
        Person::eat();
        cout << "eating pork(吃肉)"<<Person::getname()<<endl;
    }
    //新加
    void smoking()
    {
        cout << "smoking " << Person::getname()<< endl;
    }
};

woman派生类

class woman :public Person {
private:
    int m_clothes;//衣服数
public:
    woman() :Person() {//默认构造
        cout << "woman() :Person() called " << endl;
    }
   woman(const char* name, int age, float height, float weight, int num) :Person(name,
        age, 'F', height, weight), m_clothes(num) {//普通股构造函数
        cout << "woman(const char* name, int age, float height, float weight,int num) called" << endl;
    }
    ~woman() {//析构函数
        cout << "~woman() called " << endl;
    }
public:
    //行为
    void eat() {
        Person::eat();
        cout << "eating vegetables(吃蔬菜)"<<Person::getname() << endl;
    }
    //新加
    void buy()
    {
        cout << "buying " << Person::getname() << endl;
    }
};

main主函数

int main()
{
    man tom("tom",27,1.83f,72.1f,2);
    woman lily("lily",25,1.71f,61.2f,100);
    if (tom.ishealth()) {
        tom.eat();
        tom.smoking();
    }
    else {
        cout << "healthy warning " << tom.getname()<<endl;
    }

    if (lily.ishealth()) {
        lily.eat();
        lily.buy();
    }
    else {
        cout << "healthy warning " <<lily.getname()<< endl;
    }

    Person* p = new man("jerry",21,1.78f,72.1f,3);
    if (p->ishealth()) {
        p->eat();//调用的是派生类中的,多态
        //基类中无smoking
    
    delete p;//释放p指向的内存之前,会调用派生类的析构函数
    //和基类的析构函数,前提是基类的析构函数前有virtual
}

注意

  1. delete p; //释放p指向的内存之前,会调用派生类的析构函数
    //和基类的析构函数,前提是基类的析构函数前有virtual

结果展示

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值