自学C++(5)

目录

1.继承基本语法

 2.继承方式

3.继承后子类的内存空间

 4.构造子类对象时,父类和子类的构造、析构顺序

5.父类中自定义了有参构造函数,子类继承时提示语法错误问题的解决

 6.父类子类中同名成员如何访问

 7.父类子类中同名静态成员如何访问

 8.多继承

9.菱形继承

​编辑


C++中子类可以继承父类中的成员,达到减少代码量的作用。此外,子类的内部也可以写上自身特殊的成员。

1.继承基本语法

下面是父类

下面是子类的写法

class  子类  :public(继承方式)  父类 

 2.继承方式

继承方式一共三种:

(1)公共继承;(2)私有继承;(3)保护继承

首先,父类中的private成员子类无论用哪种继承方式都无法访问

如果是公共继承,则子类中原父类的成员权限均不改变;

如果是保护继承,则子类中原父类的所有除private外的成员都变成protected类型;

如果是保护继承,则子类中原父类的所有除private外的成员都变成private类型。

再复习一下,一个类中的public成员,类外可以输出、修改;其它类型的成员类外不能输出、修改,简而言之就是无法访问。

3.继承后子类的内存空间

子类完全继承父类中的所有成员,因此子类的内存空间必须额外加上父类的内存空间。

 4.构造子类对象时,父类和子类的构造、析构顺序

先构造父类、再构造子类,然后析构子类,最后析构父类

5.父类中自定义了有参构造函数,子类继承时提示语法错误问题的解决

#include<iostream>
using namespace std;

class Person{
	public:
		int age;
		Person(int a){
			age = a;
			cout<<"父类构造函数"<<endl;
		}
	protected:
		int height;
	private:
		int weight;
		
};

class child : public Person{
	public:
		int growRate;
};

int main()
{
	child c1;
	cout<<sizeof(c1);
	return 0;
}

上面的代码在编译时会发生错误,原因是子类实例化时父类构造也会运行,而且是会无条件的调用父类无参构造。这里由于只声明了父类有参构造,C++不提供默认无参构造,因此无法构造出父类,子类就无法构造,因此报错。只需补全父类的无参构造即可。

另一个注意点是:子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。

 6.父类子类中同名成员如何访问

直接写c1.age,则默认访问的是子类中的age变量,访问父类中的age变量要写成c1.Person::age。当然,对于同名函数来说,和同名变量的格式一样。注意这个时候,父类中的函数重载不能作为区分子类、父类同名函数的依据。

#include<iostream>
using namespace std;

class Person{
	public:
		int age;
		Person(){
			age = 100;
		}
		func(){
			cout<<"Person - func() is called"<<endl;
		}
		func(int a){
			cout<<"Person - func(int a) is called"<<endl;
		}
	protected:
		int height;
	private:
		int weight;
		
};

class child : public Person{
	public:
		int age;
		child(int a){
			age=a;
		}
		func(){
			cout<<"child - func() is called"<<endl;
		}
};

int main()
{
	child c1(1);
	cout<<c1.age<<' '<<c1.Person::age<<endl;
	c1.func();
	c1.Person::func(); 
//	c1.func(10);
//上面这一行报错,应该改成下面的形式
	c1.Person::func(10);
	return 0;
}

 7.父类子类中同名静态成员如何访问

同名静态成员变量:

Son::Base::m_A也可以直接写成Base::m_A,二者结果相同,但是意义不一样。

前者意为通过子类访问其父类作用域下的m_A,后者直接访问父类作用域下的m_A。

 8.多继承

9.菱形继承

 

为了解决菱形继承带来的问题,需要在羊驼类继承的两个父类加上virtual关键字,具体格式如下: 

 加上virtual之后,实际上age就保留一份,因此不再存在二义性:

 虚继承的底层实现:

左边是虚继承后的对象模型,右边是之前的对象模型。

 实际上,被标记为虚继承类型之后,羊类和驼类中的int m_Age消失了,取而代之的是一个虚基类指针(vbptr),这个指针指向一个虚基类表(vbtable),表中记录的是一个偏移量,这样一来,羊类下的虚基类指针指向的是指针位置加上指针记录的偏移量,最终正好是其父类中的int m_Age,驼类同理。这样就将原来的两个int变量减少到了如今的1个int变量,不过多了两个指针的占用空间(8字节)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值