• C++15 ---继承2:重载与覆盖、隐藏、拷贝构造函数、赋值运算符重载、静态数据成员


    一、重载与覆盖的特征

    1、重载

    函数名相同,函数参数列表不同,和返回值无关,和const有关
    成员函数被重载的特征:
    (1)相同的范围(在同一个类中);
    (2)函数名字相同;
    (3)参数不同;
    (4) virtual关键字可有可无。

    2、覆盖

    覆盖是指派生类函数覆盖基类函数,特征是:
    (1)不同的范围(分别位于派生类与基类);
    (2)函数名字相同;
    (3)参数相同;
    (4)基类函数必须有virtual关键字。

    二、隐藏

    派生类的成员函数和基类的函数同名同参,则将基类的函数隐藏。

    这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

    (1)如果派生类的函数与基类的函数同名,但是参数不同
    此时,不论有无 virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
    (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。
    此时,基类的函数被隐藏(注意别与覆盖混淆)。

    1、继承关系的类
    2、父子类的同名同参函数不能为虚

    示例代码1:

    class A
    {
    public:
    	void print() { cout << "A::print" << endl; }
    };
    /*
    隐藏:派生类的成员函数和基类的函数同名同参,则将基类的函数隐藏
    */
    class B :public A
    {
    public:
    	//print将派生下来的A的print隐藏了
    	void print() 
    	{
    		cout << "B::print" << endl; 
    	}
    };
    void main()
    {
    	A a;
    	B b;
    	a.print();
    	b.print();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    运行结果:

    在这里插入图片描述

    示例代码2:

    class A
    {
    public:
    	void print() { cout << "A::print" << endl; }
    protected:
    	int m_i;
    };
    /*
    隐藏:派生类的成员函数和基类的函数同名同参,则将基类的函数隐藏
    */
    class B :public A
    {
    public:
    	//print将派生下来的A的print隐藏了
    	void print() 
    	{
    		cout << "B::print" << endl; 
    		cout << m_i << " " << A::m_i << endl;
    	}
    	void set() { m_i = 10; A::m_i = 20; }
    protected:
    	int m_i;
    };
    void main()
    {
    	A a;
    	B b;
    	a.print();
    	b.set();
    	b.A::print();
    	b.print();
    	cout << sizeof(B) << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    运行结果:

    在这里插入图片描述

    三、继承的有参无参构造函数注意点-有无参构造,并且有指针数据成员。

    对于以下代码,无法正常实现

    class Person
    {
    public:
    	Person(){cout << "Person()" <<endl;}
    	Person(const char *name,char sex,int age):m_sex(sex),m_age(age)
    	{
    		m_name = new char[strlen(name) + 1];
    		strcpy_s(m_name,strlen(name) +1,name);
    	}
    	void print()
    	{
    		cout << m_name <<" "<< m_sex <<" "<< m_age <<" ";
    	}
    private:
    	char *m_name;
    	char m_sex;
    	int m_age;
    };
    
    class Student:public Person
    {
    public:
    	Student(){cout << "Student()" <<endl;}
    	Student(int num,const char *name,char sex,int age,int score):Person(name,sex,age),m_num(num),m_score(score){}
    	void print()
    	{
    		cout << m_num << " ";
    		Person::print();
    		cout << m_score << endl;
    	}
    private:
    	int m_num;
    	int m_score;
    };
    
    void main()
    {
    	Student s;
    	Student s1(1001,"yasuo",'f',21);
    
    	s.print();//error,出错点
    	s1.print();
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    理解:

    Person类和Student类的内存布局:
    在这里插入图片描述
    而主程序定义了无参对象s和有参对象s1.
    而无参对象s,构造时,没能为其中的指针char *m_name;开辟空间,
    就例如下述代码:

    void main()
    {
    	int *p;
    	cout << p << endl;//erroe,其没有指向合法的内存空间
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    解决方法:

    有无参构造,并且有指针数据成员。需要在无参构造函数里为其开辟空间,一个空间作为占位符。

    class Person
    {
    public:
    	//Person():m_sex('f'),m_age(20)
    	Person()
    	{
    		m_name = new char[1];
    		*m_name = '\0';
    	}
    	Person(const char *name,char sex,int age):m_sex(sex),m_age(age)
    	{
    		m_name = new char[strlen(name) + 1];
    		strcpy_s(m_name,strlen(name) +1,name);
    	}
    	~Person()
    	{
    		if(m_name != NULL)
    		{
    			delete[]m_name;
    			m_name = NULL;
    		}
    	}
    private:
    	char *m_name;
    	char m_sex;
    	int m_age;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    四、继承的拷贝构造函数、赋值运算符重载使用:

    示例代码:

    class Person
    {
    public:
    	Person():m_sex('f'),m_age(20)
    	{ 
    		m_name = new char[1];
    		*m_name = '\0';
    		cout << "Person()" << endl; 
    	}
    	Person(const char* name, char sex, int age):m_sex(sex),m_age(age)
    	{
    		m_name = new char[strlen(name) + 1];
    		strcpy_s(m_name, strlen(name) + 1, name);
    	}
    	Person(Person& p) :m_sex(p.m_sex), m_age(p.m_age)//拷贝构造函数
    	{
    		m_name = new char[strlen(p.m_name) + 1];
    		strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
    	}
    	Person& operator=(Person& p)//赋值运算符重载
    	{
    		if (this == &p)
    			return *this;
    		delete[]m_name;
    		m_name = new char[strlen(p.m_name) + 1];
    		strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
    		
    		m_sex = p.m_sex;
    		m_age = p.m_age;
    		return *this;
    	}
    	void print()
    	{
    		cout << m_name << " " << m_sex << " " << m_age << " ";
    	}
    	~Person()
    	{
    		if (m_name != NULL)
    		{
    			delete[]m_name;
    			m_name = NULL;
    		}
    	}
    private:
    	char* m_name;
    	char m_sex;
    	int m_age;
    };
    class Student :public Person
    {
    public:
    	Student():m_num(0),m_score(0) { cout << "Student()" << endl; }
    	Student(int num, const char* name, char sex, int age, int score):m_num(num),Person(name,sex,age),m_score(score) {}
    	void print()
    	{
    		cout << m_num << " ";
    		Person::print();
    		cout << m_score << endl;
    	}
    	Student(Student& s) :Person(s), m_num(s.m_num), m_score(s.m_score) {}//拷贝构造函数
    	Student& operator=(Student& s)//赋值运算符重载
    	{
    		if (this == &s)
    			return *this;
    		Person::operator=(s);
    		m_num = s.m_num;
    		m_score = s.m_score;
    		return *this;
    	}
    private:
    	int m_num;
    	int m_score;
    };
    
    void main()
    {
    	Student s;
    	Student s1(1001, "zhangsan", 'f', 20, 78);
    	s.print();
    	s1.print();
    	Student s2(s1);//调用拷贝构造函数
    	s2.print();
    	s = s1;//调用赋值运算符重载
    	s.print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    运行结果:

    在这里插入图片描述

    五、继承情况下静态数据成员的使用

    基类继承后,子类也有对静态数据成员的使用权,是共享的。
    但不占类内空间。

    示例代码:

    class Person
    {
    public:
    	Person(int num = 1000) :m_num(num) {}
    	void print()
    	{
    		cout << "count = " << m_count << endl;
    	}
    protected:
    	int m_num;
    	static int m_count;//静态数据成员
    };
    
    int Person::m_count;//外部二次声明,对该静态成员进行初始化
    
    //三个继承类:
    class Student :public Person
    {
    public:
    	Student(int num, const char* job) :Person(num)
    	{
    		m_job = new char[strlen(job) + 1];
    		strcpy_s(m_job, strlen(job) + 1, job);
    		m_count++;
    	}
    private:
    	char* m_job;
    };
    class Teacher :public Person
    {
    public:
    	Teacher(int num,const char*job):Person(num) 
    	{
    		m_job = new char[strlen(job) + 1];
    		strcpy_s(m_job, strlen(job) + 1, job);
    		m_count++;
    	}
    private:
    	char* m_job;
    };
    class Worker :public Person
    {
    public:
    	Worker(int num,const char*job) :Person(num)
    	{
    		m_job = new char[strlen(job) + 1];
    		strcpy_s(m_job, strlen(job) + 1, job);
    		m_count++;
    	}
    private:
    	char* m_job;
    };
    void main()
    {
    	Student s(1001, "student");
    	Teacher t(1002, "teacher");
    	Worker w(1003, "worker");
    	w.print();
    	t.print();
    	s.print();
    	Worker w1(1006, "worker");
    	s.print();
    	cout << sizeof(Worker) << endl;//为8字节,静态数据成员不占类的内存单元
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    运行结果:

    在这里插入图片描述

  • 相关阅读:
    MyBatis中的$和#,你知道他们的区别吗?
    R语言替换字符串中指定字符的子串:sub函数查找字符串中第一个匹配到的子串并替换、如果要删除指定字符串子串则将替换的子符串设置为空字符串
    计算机网络产生的基础是什么
    技术人必看!数据治理是什么?它对数据中台建设重要吗?
    3.4 - 编译与解释 3.5 - 编译过程 3.8 - 文法
    带负电荷羧基化/异性电荷PH响应性非球形/电荷磺酸基/电荷羧基聚苯乙烯微球研究步骤
    Qt中的JSON支持
    计算机底层原理
    java计算机毕业设计农田节水灌溉监测系统源码+程序+lw文档+mysql数据库
    如何一个模型走天下?集成训练多数据集,打造通用目标检测模型方法详解
  • 原文地址:https://blog.csdn.net/kyrie_sakura/article/details/127868597