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

本文详细介绍了C++中的继承特性,包括函数的重载、覆盖和隐藏。重载关注同名函数的参数列表不同,覆盖涉及派生类对基类函数的替换,而隐藏则是派生类同名同参函数对基类函数的屏蔽。文章通过示例代码阐述了这些概念,并特别讨论了构造函数在有无参、指针成员时的注意事项,强调了正确初始化指针成员的重要性。此外,还提到了拷贝构造函数和赋值运算符在继承中的应用,以及静态数据成员在继承类中的共享特点。
摘要由CSDN通过智能技术生成

一、重载与覆盖的特征

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();

}

运行结果:

在这里插入图片描述

示例代码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;
}

运行结果:

在这里插入图片描述

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

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

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();
	
}

在这里插入图片描述

理解:

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

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

解决方法:

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

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

在这里插入图片描述

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

示例代码:

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();
}

运行结果:

在这里插入图片描述

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

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

示例代码:

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字节,静态数据成员不占类的内存单元
}

运行结果:

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值