继承那些事

继承概念:通过继承机制,可以利用已有的数据类型来定义新的数据类型,新的数据类型不仅拥有新定义的成员,而且同时还拥有旧的成员。我们称已存在的用来派生新类的类称为基类(父类),派生出来的新类称为派生类(子类)。继承提高了代码的复用率

一.继承格式


二.继承方式:

1.公有继承(public)

公有继承特点:基类的公有成员,和保护成员,私有成员作为派生类的成员时,他们 都保持原有的状态。也就是说基类的私有成员,派生类中仍然是私有的,不能被这个派生类子类访问。

2.私有继承(private)

私有继承的特点:基类的公有成员私有成员,保护成员都作为派生类的私有成员。并且全都不能被这个派生类子类访问

3.保护继承(protected)

保护继承的特点:基类的公有成员,保护成员都作为派生类的保护成员,可以被派生类的子类访问。基类的私有成员仍作为派生类私有成员,不能被派生类子类访问

以上三种继承方式在其成员可见性方面的问题

公有继承方式

(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)

(2)基类成员对其派生类可见性:public 和protected可见,private不可见

(2)基类成员对派生类对象可见性:public可见,其他不可见

私有继承方式

(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)

(2)基类成员对其派生类可见性:public 和protected可见,private不可见

(2)基类成员对派生类对象可见性:所有成员都是不可见的

保护继承方式

(1)基类成员对其对象可见性:public可见,其他不可见(这里protected相当于private)

(2)基类成员对其派生类可见性:public 和protected可见,private不可见

(2)基类成员对派生类对象可见性:所有成员都是不可见的

为了验证上述结论请看下面例子

公有继承:

class Parent//父类
{
private:
	int a;
public:
	int b;
protected:
	int c;
};
class Child :public Parent//公有继承
{
private:
public:
	    void fun()//派生类成员访问基类
         {
		   a = 10;//no
		   b = 10;//yes
		   c = 10;//yes
         }
protected:
};
int main()
{
	Parent e;//基类对象访问基类成员
	e.a = 10;//no
	e.b = 10;//yes
	e.c = 10;//no
	Child d;//派生类对象访问基类成员
	d.a = 10;//no
	d.b = 10;//yes
	d.c = 10;//no
}

私有继承:

class Parent//父类
{
private:
	int a;
public:
	int b;
protected:
	int c;
};
class Child :private Parent//私有继承
{
private:

public:
	void fun()//派生类成员访问基类
	{
		a = 10;//no
		b = 10;//yes
		c = 10;//yes
	}
	
protected:
	
};
int main()
{
	Parent e;//基类对象访问基类成员
	e.a = 10;//no
	e.b = 10;//yes
	e.c = 10;//no
	Child d;//派生类对象访问基类成员
	d.a = 10;//no
	d.b = 10;//no
	d.c = 10;//no
}
保护继承:

class Parent//父类
{
private:
	int a;
public:
	int b;
protected:
	int c;
};
class Child :protected Parent//私有继承
{
private:
public:
	void fun()//派生类成员访问基类
	{
		a = 10;//no
		b = 10;//yes
		c = 10;//yes
	}
protected:
};
int main()
{
	Parent e;//基类对象访问基类成员
	e.a = 10;//no
	e.b = 10;//yes
	e.c = 10;//no
	Child d;//派生类对象访问基类成员
	d.a = 10;//no
	d.b = 10;//no
	d.c = 10;//no
}

三.继承与转换——赋值兼容规则——public继承

1.子类对象可以赋给父类对象//切片,切割

2.父类对象不可赋给子类对象

3.父类的指针/引用可以指向子类对象//切片,切割

4.子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)容易产生越界访问

以下给出代码


四:派生类默认成员函数

在继承关系中,派生类如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数


继承关系中构造函数调用顺序

先执行派生类构造函数,在派生类构造函数初始化列表调用-----------基类构造函数--------------------接着执行派生类构造函数体

验证我们上面的结论给出代码:

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& a)
	{
		cout << "A(const A& a)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
public:
	int _a;
};
class B:public A
{
public:
	B(int a, int b)
		:A(a)
		,_b(b)
	{
		cout << "B(int a,int b)" << endl;
	}
	B( B& b)
		:A(b)//切片,切割
		,_b(b._b)
	{
		cout << "B( B& b)" << endl;
	}
public:
	int _b;
};
int main()
{
	//A a(3);
	//A a1(a);
	//B b(3,4);
	B b(3,4);
	//B b2(b);
	system("pause");
}
结果:


继承关系中析构函数调用顺序
先调用派生类析构函数-----------------再(自动)调用基类析构函数

五:继承体系中的作用域

1.在继承体系中基类和派生类是两个不同作用域

2.子类和父类中有同名成员(包括成员变量,和成员函数),子类成员将屏蔽父类对成员直接访问(在子类函数中,可以使用基类::基类成员 访问)//也叫隐藏,重定义

六:友元关系不能继承,也就是说基类有元不能访问子类私有和保护成员

直接看例子

class Student;
class Person
{
public:	
	Person(int a=2)
		:_a(a)
	{}

	friend void  Display(Person& p, Student& s);
private:
	int _a;
};

class Student : public Person
{
	
protected:
	int _b;

};
void  Display(Person& p, Student& s)
{
	
	cout << p._a << endl;
	cout << s._b<< endl;//友元不能被继承,基类友元不能访问子类私有和保护成员
};
int main()
{
	Person p;
	Student s;
	Display(p, s);
	system("pause");
	return 0;
}


七:单继承,多继承,菱形继承

1.单继承:一个子类只有一个直接父类时称这个继承关系为单继承。

2.多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

3.菱形继承:就是综合了单继承,和多继承

想必大家对此都有了解,于是概念就不多说了。

菱形继承存在的问题:二义性,和数据冗余

class A
{
public:
	int _a;
};
class B:public A
{
public:
	int _b;
};
class C :public A
{
public:
	int _c;
};
class D :public B, public C
{
public:
	int _d;
};
int main()
{
	B b;
	C c;
	D d;
	//d._a//不知道访问父类B,和父类C中哪个//即二义性
	d.B::_a = 4;
	d.C::_a = 5;//以上两行代码说明了_a有两份,体现了数据冗余
}

那么如何解决数据冗余和二义性问题呢?虚继承就解决了这个问题

八:虚继承

虚继承就是指在菱形继承中将基类的数据只继承了一份。

class A
{public:
	int _a;
};
class B:virtual public A//虚继承就是在B和C继承A时,前面加virtual
{
public:
	int _b;
};
class C:virtual public A//虚继承就是在B和C继承A时,前面加virtual
{
public:
	int _c;
};
class D :public B, public C
{
public:
	int _d;
};
//对象模型——内存当中的分布
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	//cout << sizeof(d) << endl;//20不加virtual
	cout<<sizeof(d) << endl;//24加virtual
}
按理说既然继承了一份,那么就应该大小是16,为什莫是24呢?

请看下图解释的很清楚:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值