C++面向对象——继承

继承


继承的本质代码的复用

单继承

格式

class 新类的名字:继承方式 继承类的名字{};

继承方式

  • 基类中私有的在派生类中不可见 只有自己和友元能可见
  • 基类中的成员(除私有成员外)在派生类中的权限总是以安全性高(基类中的访问限定符和派生类的继承方式哪个更小)的方式呈现

安全性级别:private>protected>public

class father
{
public:
	int pub;
protected:
	int pro;
private:
	int pri;
};

class son1:public father  //将基类除private外全部都继承过来 权限不变
{
	// pub权限public  pro权限protected  pri不可见
};
class son2 :protected father  //将基类除private外全部都继承过来 权限变成protected
{
	// pub权限protected  pro权限protected  pri不可见
};
class son3 :private father  //将基类除private外全部都继承过来 权限变成private
{
	// pub权限private  pro权限private  pri不可见
};
 
  

多继承

一个类可以继承多个父类,可以从多个基类继承数据和函数。

格式

class 新类的名字:继承方式1 继承类名1,继承方式2继承类名2 {};

注意:多个父类同名成员的二义性问题——作用域

class father
{
public:
	int pub;
};

class mather
{
public:
	int pub;
};

class son:public father,public mather{};//两个父类

int main() 
{
	son s1;             //调用多个父类的同名成员编译报错
	s1.father::pub = 1; //二义性解决:作用域
}

子类的初始化和销毁原则

创建子类对象,无论时使用子类指针还是父类指针防止内存溢出

(1)初始化时,要先初始化父类,再初始化子类

为了初始化从父类继承来的成员,系统需要先调用其父类的构造函数,所以创建子类对象时:

  1. 基类有无参的构造函数,系统会先调用基类无参的构造函数
  2. 基类没有无参的构造函数,需使用初始化参数列表来显示调用有参的构造函数

(2)销毁时,要先销毁子类,再销毁父类

子类的析构函数会在执行完后调用父类的析构函数(子类析构函数最后会调用父类析构),从而确保资源能成功释放和销毁,而父类的析构函数不会调用子类的析构函数

只需调用子类的析构函数就能按照顺序成功销毁

  1. 栈区子类对象,栈区自动释放调用delete,delete在调用子类的析构函数,子类的析构函数尾会再调用父类的析构函数
  2. 子类指针指向子类对象,调用子类的析构函数后会自动调用父类的析构函数
  3. 父类指针指向子类对象
  • 需要将父类析构函数写成虚析构函数,子类析构函数重写(因为编译器会把析构函数名字都处理成destructor),调用子类析构函数(结束后会自动调用父类的析构函数)
  • 若未将父类的析构函数写成虚析构,则发生隐藏,调用(指针类型)父类析构,子类未被释放,造成内存泄露

案例

构造1——基类有无参构造

class A
{
public:
	A( )
	{
		cout << "A:无参构造" << endl;
	}
	A(int val)
	{
		cout << "A:有参构造" << endl;
	}

};

class B :public A
{
public:
	B()
	{
		cout << "B:构造" << endl;
	}
};

int main()
{
	B b; 
}
/*
A:无参构造
B:构造
*/

构造例2——基类只有有构造

class A
{
public:
	A(int val)
	{
		cout << "A:只有有参构造" << endl;
	}

};

class B :public A
{
public:
	B():A(1) //构造函数参数列表显示调用父类构造
	{
		cout << "B:构造" << endl;
	}
};

int main()
{
	B b; 
}
/*
A:只有有参构造
B:构造
*/

销毁例1——栈区子类对象

class A
{
public:
	A() 
	{
		cout << "A:构造" << endl;
	}
	~A()
	{
		cout << "A:析构" << endl;
	}
};

class B:public A
{
public:
	B()
	{
		cout << "B:构造" << endl;
	}
	 ~B()	
	{
		cout << "B:析构" << endl;
	    //调用父类析构函数
	}
};

int main() 
{
	B b;  //栈区函数结束自动调用delete销毁 delete调用子类的析构函数
}
/*
A:构造
B:构造
A:析构
B:析构
*/

销毁例2——子类指针指向子类对象

class A
{
public:
	A() 
	{
		cout << "A:构造" << endl;
	}
	~A()
	{
		cout << "A:析构" << endl;
	}
};

class B:public A
{
public:
	B()
	{
		cout << "B:构造" << endl;
	}
	 ~B()	
	{
		cout << "B:析构" << endl;
		//调用父类析构函数
	}
};

int main() 
{
	B* b=new B();  
	delete b;	//正常调用子类析构函数
}
/*
A:构造
B:构造
A:析构
B:析构
*/

销毁例3——父类指针指向子类对象 虚函数未构成重写 函数隐藏 直接delete内存泄漏(delete会调用析构函数)

class A
{
public:
	A() 
	{
		cout << "A:构造" << endl;
	}
	~A()
	{
		cout << "A:析构" << endl;
	}
};

class B:public A
{
public:
	B()
	{
		cout << "B:构造" << endl;
	}
	 ~B()		//函数隐藏	~A不是虚函数 
	{
		cout << "B:析构" << endl;
	    //调用父类析构函数
	}
};

int main() 
{
	A* a = new B();  //父类指针指向子类对象 
	delete	a;	//函数隐藏 执行指针类型 A的析构 子类未释放 内存泄漏
}
/*
A:构造
B:构造
A:析构
*/

销毁例4——父类指针指向子类对象 虚函数构成重写 直接delete 成功销毁

class A
{
public:
	A() 
	{
		cout << "A:构造" << endl;
	}
	virtual ~A()
	{
		cout << "A:析构" << endl;
	}
};

class B:public A
{
public:
	B()
	{
		cout << "B:构造" << endl;
	}
	 ~B()	
	{
		cout << "B:析构" << endl;
		//调用父类析构函数
	}
};

int main() 
{
	A* a=new B();  
	delete a;	//正常调用子类析构函数
}
/*
A:构造
B:构造
A:析构
B:析构
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值