C++中的继承

本文探讨了C++中的继承特性,包括不同继承方式下成员的权限,赋值兼容性原则,以及构造析构调用顺序。强调了子类对象可以作为父类对象使用,子类构造时需调用父类构造函数初始化继承成员,析构时需调用父类析构函数清理。还讨论了同名函数和静态成员的处理,以及C++支持的多重继承和如何解决多继承中的二义性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承方式的不同,成员变量在子类中的权限不同

继承方式publicprotectedprivate
publicpublicprotectedprivate
protectedprotectedprotecedprivate
privateprivateprivateprivate

1、子类拥有父类中所有成员变量和成员函数
2、子类就是一种特殊的父类
3、子类对象可以当做父类对象使用
4、子类也可以拥有父类没有的方法和属性

赋值兼容性原则

1、子类对象可以当做父类对象使用
2、子类对象可以直接赋值给父类对象
3、子类对象可以直接初始化父类对象
4、父类指针可以直接指向子类对象
5、父类引用可以直接引用子类对象

namespace three {
	class Parent {
	public:
		void printP() {
			printf("i am father\n");
		}
	protected:
		int a;
		int b;
	};


	class Child :public Parent {
	public:
		Child() {
			a = 0;
			b = 0;
			c = 0;
		}
		void printC() {
			printf("i am son\n");
		}
	protected:
	private:
		int c;
	};
	
	void howToPrint(Parent *p) {

		p->printP();
	}
	void howToPrint2(Parent &p) {
		p.printP();
	}
	void main_3() {
		Parent p;
		Child c;
		p.printP();
		c.printC();
		Parent * base = NULL;
		base = &c;
		base->printC();//有错,不能访问子类中的成员函数
		//可以把子类对象赋给基类指针
		//子类是一种特殊的父类
		
		base->printP();
		//子类是一种特殊的父类,可以子类当父类用
		Parent &myp = c;
		myp.printP();
		cout << endl;
		//测试父类指针,做函数参数
		howToPrint(&p);
		howToPrint(&c);

		//测试引用
		howToPrint2(p);
		howToPrint2(c);
		//可以用子类对象来初始化父类对象
		//父类
		//编译器提供的行为
		Parent p3 = c;	
	}
}

继承中的构造析构调用原则:
1、子类对象在创建时会首先调用父类的构造函数,记得初始化父类带参构造函数
2、父类构造函数在执行结束后,执行子类的构造函数
3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
4、析构函数再用的先后顺序和构造函数相反。

原则:

先构造父类,再构造成员变量、最后析构自己
先析构自己,再析构成员变量、最后析构父类
记住:先构造的对象,后释放。

没有父类哪有子类,先调用父类构造函数
在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化
在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理

继承中的同名函数和变量,显示调用

using namespace std;
class Parent {
public:
	int a;
	int b;
	void print() {
		printf("father--->b:%d\n", b);
	}
protected:
private:

};

class Child :public Parent {
public:
	int b;
	int c;
	void print() {
		printf("son--->b:%d\n", b); 
	}
protected:
private:

};
void main_5() {
	Child b1;
	b1.b = 10;
	b1.Parent::b = 2;//要调用父类的b,需要加上Parent
	b1.print();
	b1.Parent::print();
}

继承中的static

记得在类外要初始化,不仅仅是初始化,也是分配内存的意思。

namespace staic {
	class A {
	public:
		//单例的时候才设置成私有的
		A() {
			//cout<<a<<endl;
		}
	public:
		static int a;
		int b;
		void print() {
			printf("father--->b:%d\n", b);
			printf("father--->a:%d\n", a);
			
		}
	protected:
	private:

	};
	int A::a = 10;//不仅仅是初始化,还要告诉c++编译器,分配内存
	class B :private A {
	public:
		//int b;
		int c;
		void print() {
			printf("son---@b:%d\n", b);
			printf("son---->a%d\n", a);
		}
	protected:
	private:

	};
}
using namespace staic;
void main() {
	A a;
	B b;
	b.print();
}

多重继承

Java中支持单继承,C++支持多继承,这是历史遗留问题,C++出现的比较早,Java出现的比较晚,Java支持接口的多继承。
C++多继承完全可以通过,单继承来实现,而且多继承带来的复杂性,远远大于它的方便性。所以开发中一般使用多继承。

多继承中的二义性

class  A{
public:
	int i;	
};

class  B1: virtual public A{
public:
	
};
class  B2:virtual public A{
public:
		
};
class C:public B1,public B2{
public:
	int get(){
    	return i;//这里会出现,i不明确。通过加virtual关键字来解决
	}
}

通过虚继承来解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值