类与类之间的关系之——继承

这篇博客探讨了类与类之间的三大关系——组合、代理和继承,并详细阐述了继承的特点,包括权限继承、构造过程、成员方法的隐藏与覆盖。文章通过代码示例解释了如何在子类中调用父类的隐藏方法,以及虚函数在继承中的作用,特别是析构函数的虚函数特性,以防止内存泄漏问题。

一、类与类之间的三大关系

(1)组合:一个类是另一个类的一部分

class A
{
	class B
	{};
};

(2)代理:一个类的方法是另一个类方法的子集,也就是说这个类它本身是不进行任何的操作,只是调用另一个类来帮它实现它想做的事情。

(3)继承:一个类是另一个类的一种

class Parent
{
	
};

class child : public Parent
{

};

二、对于父类中三种权限的成员变量以及成员方法被子类继承后的特点

父类继承方式子类外界
publicpublicpublic可以访问
protectedprotect不能被访问
privateprivate
protectedpublicprotected不能被访问
protectedprotected
privateprivate
privatepublic能继承,不能访问不能被访问
protected
private

注:(1)在继承的时不写继承权限时默认private权限继承

        (2)继承以后,以继承时的权限和本身的权限保密等级高的为主

三、构造:先构造父类,再构造子类,也就是说在子类构造之前就要先构造父类

class A
{
public:
	A(int tmp = 10)  
	{
		a = tmp;
	}

	int a;
};

class Aa : public A
{
public:
	Aa(int tmp1, int tmp2)
		:A(tmp1)//先构造父类  //如果在这里写:a(tmp1)那就是错误的,这个是赋值不是初始化
	{
		a = tmp1;
		a1 = tmp2;	
	}

	int a;
	int a1;

};

四、成员方法之间的三大关系

(1)重载

     条件:作用域相同、函数名相同、参数列表不同

               显然父类和子类是两个不同的作用域,所以继承中不存在重载

(2)隐藏:子类会隐藏父类中成员方法名相同的成员方法

      代码解释:

class B
{
public:
	void showa()
	{
		cout<<"B::void showa()"<<endl;
	}
	void showb()
	{
		cout<<"B::void showb()"<<endl;
	}
	void show()
	{
		cout<<"B::void show()"<<endl;
	}
};

class D : public B
{
public:
	void showa()
	{
		cout<<"D::void showa()"<<endl;
	}
	void showb(int b)
	{
		cout<<b<<"D::void showb()"<<endl;
	}
	int show()
	{
		cout<<"D::int show()"<<endl;
		return 0;
	}
};

int main()
{
	B b;
	b.show();
	b.showa();
	b.showb();
	D d;
	d.show();
	d.showa();
	d.showb(10);
	return 0;
}

结果展示:

根据结果我们发现,不论是子类定义的对象还是父类定义的对象,在调用成员方法的时候都调用的是子类的成员方法,这时我们称子类隐藏了父类同名的成员方法,根据上面代码的验证,不管返回值、参数列表是否相同,只要函数名相同就会被隐藏。

  如果要调用父类的成员方法怎么做呢?(即调用被隐藏的成员方法)加上作用域即可

 代码修改

//上面类的代码与上一个代码完全一样,不再重写
int main()
{
	B b;
	b.B::show();
	b.B::showa();
	b.B::showb();
	D d;
	d.B::show();
	d.B::showa();
	d.B::showb();
	return 0;
}

结果展示:

(3)覆盖(重写):只会发生在虚函数列表中,如果子类成员方法与父类中虚函数同名、同返回值、同参数列表,则子类中的函数会覆盖虚函数并将本类中的这个函数地址cunzau虚函数列表中

    在继承关系中提供的由子类构造父类的构造方法:先利用子类构造一个父类对象,用父类对象给 an (代码中定义的一个父类对象)赋值

子类对象 = 父类对象 // 这种构造是错误的,因为子类继承了父类,如果这样写就是增加了无效的访问空间
父类对象 = 子类对象  //这种构造方法正确

子类指针 = 父类指针  //错误,与上面的相同,当子类访问子类本身的成员或成员方法时,它已经不存在了
父类指针 = 子类指针  //正确

虚函数表

    父类中的虚函数继承到子类依旧是虚函数(子类中与与父类同返回值、同函数名、同参数列表时,子类中的这个方法也是虚函数)

    先析构子类,后析构父类,又因为是继承关系,所以在调用子类析构之后会自动调用父类的析构

class Animal
{
public:
	Animal(char* name)
	{
		_name = new char[strlen(name) + 1];
		strcpy_s(_name,strlen(name) + 1,name);
	}
	void eat()
	{
		cout<<_name<<":eat eat eat"<<endl;
	}
	void call()
	{
		cout<<_name<<" wo ye bu zhi dao jiao sha"<<endl;;
	}
	~Animal()
	{
		cout << "Animal::~Animal()" << endl;
		if(NULL != _name)
		{
			delete[]_name;
		}
	}
protected:
	char* _name;
};

class Dog : public Animal
{
public:
	Dog(char* name)
		:Animal(name)
	{}
	void call()
	{
		cout<<_name<<"wang wang wang"<<endl;
	}
	~Dog()
	{
		cout<<"~Dog()"<<endl;
	}
	char* _name;
};
int main
{
    Animal *pa = new Dog("dog");  
	delete pa;
}

结果展示:

我们发现它只调用了父类的析构,而没调用子类的,所以这一定会造成一定的内存泄漏,但是上面说了,调用子类的析构之后会自动调用父类的析构,所以我们现在只需要调用子类的析构即可,但是怎么调用呢,指针是父类的指针,人家调用的肯定是自己的析构呀,所以这里我们用到虚函数

    虚函数表:里面存的是虚函数的入口地址

覆盖只可能发生在虚函数的情况下,为解决上述问题,我们将父类的析构函数设成虚函数,那么它就会存在虚函数表中,而又让父类指向了子类,所以当子类发现它是虚函数的时候,它就会去虚函数表中找到这个函数析并将它覆盖,此时再调用的时候就会调用这个虚函数,从而实现了两个都被析构

代码展示:

class Animal
{
public:
	Animal(char* name)
	{
		_name = new char[strlen(name) + 1];
		strcpy_s(_name,strlen(name) + 1,name);
	}
	void eat()
	{
		cout<<_name<<":eat eat eat"<<endl;
	}
	void call()
	{
		cout<<_name<<" wo ye bu zhi dao jiao sha"<<endl;;
	}
	virtual~Animal()
	{
		cout << "Animal::~Animal()" << endl;
		if(NULL != _name)
		{
			delete[]_name;
		}
	}
protected:
	char* _name;
};

class Dog : public Animal
{
public:
	Dog(char* name)
		:Animal(name)
	{}
	void call()
	{
		cout<<_name<<"wang wang wang"<<endl;
	}
	~Dog()
	{
		cout<<"~Dog()"<<endl;
	}
	char* _name;
};

int main()
{
	Dog dog("dog");
	Animal an("animal");
	Dog *Pd = &dog;
	Animal *Pa = &an;
	Pa = Pd;
}

结果展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值