c++继承

继承:

#include<stdio.h>
#include<iostream>
class base
{
public:
	int m_a;
protected:
	int m_b;
private:
	int m_c;
};

class son:public base
{
public:
	int m_d;
};
void test01()
{

	std::cout<<"sizeof of son="<<sizeof(son)<<std::endl;
}

int main()
{
	test01();
	return 0;
}

执行上面代码得到的结论:

父类中所有非静态成员属性都会被继承下去

父类中私有成员属性,是被编译器给隐藏了,因此是访问不到的,但是确实是被继承下去了

利用开发人员命令提示工具查看对象模型

跳转盘符  (你的文件所在的盘符)比如C:

跳转文件路径 cd 具体路径下

查看命名cl /d1 reportSingleClassLayout类名 文件名

 

这样也能看到!!

 

继承中构造和析构顺序

#include<stdio.h>
#include<iostream>
class base
{
public:
	base()
	{
		std::cout << "base构造" << std::endl;
	}
	~base ()
	{
		std::cout << "~base析构" << std::endl;
	}
};

class son :public base
{
public:
	son()
	{
		std::cout << "son构造" << std::endl;
	}
	~son()
	{
		std::cout << "~son析构" << std::endl;
	}
};
void test01()
{
	base fa;
	son so;
	
}

int main()
{
	test01();
	return 0;
}

结论:先构造父类,在构造子类,析构的顺序与构造的顺序相反

继承中同名的成员处理方式

问题:当子类与父类出现同名的成员,如何让通过子类对象,访问到子类或父类中同名的数据呢?

访问子类同名成员 直接访问即可

访问父类同名成员 需要加作用域

#include<stdio.h>
#include<iostream>
class base
{
public:
	base()
	{
		m_a = 100;
	}
	int m_a;
};
class son:public base
{
public:
	son()
	{
		m_a = 200;
	}
	int m_a;
};

//同名成员属性的处理方式
void test01()
{
	base b;
	son s;
	std::cout << "son下的 m_a= " << s.m_a << std::endl;
     //如果通过子类对象访问到父类中的同名成员,需要加作用域
	std::cout << "base下的m_a= " << s.base::m_a << std::endl;
	
}
//同名成员是属性的处理方式

int main()
{
	test01();
	return 0;
}

    总结:子类对象可以直接访问到子类的同名成员

             子类对象加作用域可以访问到父类的同名成员

            当子类和父类拥有同名的成员函数,子类会隐藏父类中同名的成员函数,加作用域可以访问到父类中同名的成员函数

 

继承中同名的静态成员的处理方法

问题:继承中同名的静态成员在子类对象上面如何进行访问?

静态成员和非静态成员出现同名,处理方式一致

访问子类同名成员,直接访问即可

访问父类同名成员,需要加作用域

#include<stdio.h>
#include<iostream>
class base
{
public:
	static void func()
	{
		std::cout << "base静态" << std::endl;
	}
      static int m_a;
};
int base::m_a = 100;
class son:public base
{
public:
	static void func()
	{
		std::cout << "son 静态" << std::endl;
	}

	static int m_a;
};
int son::m_a = 200;


void test01()
{
	son s;
	//通过对象来访问数据
	std::cout << "son 下面的s.m_a=" << s.m_a << std::endl;
	std::cout << "base下面的s.m_a=" << s.base::m_a << std::endl;
	//通过类名来访问数据
	std::cout << "通过类名访问" << std::endl;
	std::cout << "son下m_a=" << son::m_a << std::endl;
	std::cout << "son下m_a=" << son::base::m_a << std::endl;
	//第一个双冒号代表通过类名的方式访问
	//第二个双冒号代表访问父类作用域下的
}
void test02()
{
	//通过对象访问
	son s;
	s.func();
	s.base::func();

	//通过类名访问
	son::func();
	son::base::func();

}

int main()
{
	test01();
	test02();
	return 0;
}

子类出现和父类同名静态成员函数,也会隐藏父类中所有同名成员函数

如果想访问父类中被隐藏同名成员,需要加作用域

总结:同名静态成员吃力方式和非静态吃力方式一样,只不过有两种访问的方式(通过类名或者通过对象)

多继承语法

c++允许一个类继承多个类

语法:class 子类:继承方式 父类1,继承方式 父类2......

多继承中可能会引发父类中有同名成员 出现,需要加作用域区分

        比如一个子类继承了父类1,和父类2,这两个父类中有同名的成员,通过总类访问不同父类中的数据,应该加上作用域来区分

c++实际不建议多继承

菱形继承(钻石继承)

菱形继承的概念:

  • 两个派生类继承同一个基类
  • 又有某个类同时继承这两个派生类
  • 这种继承被称为菱形继承。或者钻石继承

菱形继承问题:

  • 1.羊继承了动物的数据,驼同样继承了动物的数据,当羊驼使用数据时就会产生二义性(到底是羊的,还是 驼的)
  • 2.羊驼继承动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以
#include<iostream>
using namespace std;
//动物类
class Animal
{
public:
	int m_age;

};
//羊类
class sheep :public Animal
{
};
//驼类
class tuo:public Animal
{

};
//羊驼类
class sheeptuo :public sheep,public tuo
{

};
void test01()
{
	sheeptuo st;
	//st.m_age =18;//产生了 二义性 加上作用域就可以访问

	//但是这份数据我们只需要一份就可以,菱形继承导致了数据有两份导致了资源浪费
	st.sheep::m_age =19;
	st.tuo::m_age =28;
	cout<<"st.sheep::m_age="<<st.sheep::m_age<<endl;
	cout<<"st.tuo::m_age="<<st.tuo::m_age<<endl;
}

int main()
{
	test01();
	return  0;
}

解决的:利用虚继承解决菱形继承的问题 继承之前加上关键字virtual 变为虚继承 Animal 类变为虚基类

#include<iostream>
using namespace std;
//动物类
class Animal
{
public:
	int m_age;

};
//羊类
class sheep :virtual public Animal
{
};
//驼类
class tuo:virtual public Animal
{

};
//羊驼类
class sheeptuo :public sheep,public tuo
{

};
void test01()
{
	sheeptuo st;
	st.m_age =18;

	
	st.sheep::m_age =19;
	st.tuo::m_age =28;
	cout<<"st.m_age="<<st.m_age<<endl;//不会出现不明确的情况
	cout<<"st.sheep::m_age="<<st.sheep::m_age<<endl;
	cout<<"st.tuo::m_age="<<st.tuo::m_age<<endl;
}

int main()
{
	test01();
	return  0;
}

虚继承的内部剖析:

 

 

简述C++中虚继承的作用及底层实现原理?

  • 每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)
  • 虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了
  • 当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
  • 实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。
  • 我的理解是通过偏移地址,找到虚基类成员,如果两个父类的父类是一个类,类似于B的父类是A,C的父类是A,B,C父类相同,那么我们不需要两份相同的继承。

 

       

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值