C++ 菱形继承

本文探讨了C++中的模板继承、菱形继承和虚继承的概念及其应用场景。模板继承展示了不同类型的Object实例如何共享静态成员。菱形继承示例说明了数据冗余问题,而虚继承则作为解决方案,防止数据不一致。此外,还讨论了虚函数在菱形继承中的作用,解释了如何通过虚函数表实现多态调用。
摘要由CSDN通过智能技术生成

模板继承

template<class T>
class Object
{
	T value;
public:
	Object(T x = T()) : value(x) {}
	static int num;
};
template<class T>
int Object<T>::num = 0;

class Base :public Object<int>
{
public:
	Base() 
	{
		num += 1;
	}
	void Print() const
	{
		cout << "Base:" << num << endl;
	}
};

class Test :public Object<int>
{
public:
	Test() 
	{
		num += 1;
	}
	void Print() const
	{
		cout << "Test:" << num << endl;
	}
};

int main()
{
	Base b1, b2;
	Test t1, t2;
	b1.Print();
	t1.Print();

	return 0;
}

在这里插入图片描述
我们可以很明确的看出应该输出4,4,但是如果我们将继承Object的类型进行修改

template<class T>
class Object
{
	T value;
public:
	Object(T x = T()) : value(x) {}
	static int num;
};
template<class T>
int Object<T>::num = 0;

class Base :public Object<int>
{
public:
	Base() 
	{
		num += 1;
	}
	void Print() const
	{
		cout << "Base:" << num << endl;
	}
};

class Test :public Object<double> // 这里由int 修改为 double
{
public:
	Test() 
	{
		num += 1;
	}
	void Print() const
	{
		cout << "Test:" << num << endl;
	}
};

int main()
{
	Base b1, b2;
	Test t1, t2;
	b1.Print();
	t1.Print();

	return 0;
}

在这里插入图片描述

可以看出两个类型的Object拥有各自的num,那么打印出来的结果就是2,2
在这里插入图片描述

菱形继承

在这里插入图片描述
这里就可以看到,Stud_Elem类对象,内存结构中出现了两次Person类,继而出现了信息冗余的问题

class Person
{
private:
	string p_id;
	string p_name;
	string p_sex;
	int p_age;
public:
	Person(const string& id, const string& name, const string& sex, int age)
		:p_id(id), p_name(name), p_sex(sex), p_age(age)
	{}
	void print()const
	{
		cout << "id:" << p_id << endl;
		cout << "name:" << p_name << endl;
		cout << "sex:" << p_sex << endl;
		cout << "p_age:" << p_age << endl;
	}
};

class Student :public Person
{
private:
	string s_id;
public:
	Student(const string& id, const string& name, const string& sex, int age, string& d)
		:Person(id,name,"man",age),s_id(d)
	{}
};
class Staff : public Person
{
private:
	string s_id;
public:
	Staff(const string& id, const string& name, const string& sex, int age, const string& d)
		:Person(id, name, "woman", age), s_id(d)
	{}

};

class Stud_Staff : public Student, public Staff
{
private:
public:
	Stud_Staff(const string& id, const string& name, int age, const string& dd, string ss)
		:Student(id, name, "nan", age, ss), Staff(id, name, "woman", age, dd)
	{}
};

int main()
{
	Stud_Staff ss("123456789", "zyq", 20, "2020", "3030");
	ss.Student::print();
	ss.Staff::print();

	Student s1 = ss;
	Staff s2 = ss;
	//Person p = ss;  error!!! 数据不一致性
}

虚继承

解决数据冗余与数据不一致性的方案就是进行虚继承
在这里插入图片描述
当 Student 类与 Staff 类虚继承于Person类
在这里插入图片描述

class Person
{
private:
	string p_id;
	string p_name;
	string p_sex;
	int p_age;
public:
	Person(const string& id, const string& name, const string& sex, int age)
		:p_id(id), p_name(name), p_sex(sex), p_age(age)
	{}
	void print()const
	{
		cout << "id:" << p_id << endl;
		cout << "name:" << p_name << endl;
		cout << "sex:" << p_sex << endl;
		cout << "p_age:" << p_age << endl;
	}
};

class Student :virtual public Person
{
private:
	string s_id;
public:
	Student(const string& id, const string& name, const string& sex, int age, string& d)
		:Person(id, name, "man", age), s_id(d)
	{}
};
class Staff :virtual public Person
{
private:
	string s_id;
public:
	Staff(const string& id, const string& name, const string& sex, int age, const string& d)
		:Person(id, name, "woman", age), s_id(d)
	{}

};

class Stud_Staff : public Student, public Staff
{
private:
	int num = 10;
public:
	Stud_Staff(const string& id, const string& name, int age, const string& dd, string ss)
		:Student(id, name, "nan", age, ss), Staff(id, name, "woman", age, dd), Person("60101", "zyq", "man", 20)
	{}
};

int main()
{
	Stud_Staff ss("123456789", "zyq", 20, "2020", "3030");
	ss.Student::print();
	ss.Staff::print();

	Student s1 = ss;
	Staff s2 = ss;
	Person p = ss;
}
class Object
{
	int value;
public:
	Object(int x = 0) :value(x) {}
};
class Base :virtual public Object
{
	int num;
public:
	Base(int x = 0) :num(x), Object(x + 10) 
	{}
};
class Test :virtual public Object
{
	int sum;
public:
	Test(int x = 0) :sum(x), Object(x + 10) 
	{}
};
class Det :public Base, public Test
{
private:
	int total;
public:
	Det(int x = 0) :total(x), Base(x + 10), Test(x + 20), Object(x + 30)
	{}
};

int main()
{
	Det d(0);
	return 0;
}

在这里插入图片描述
由于每次程序编译链接时,每一次运行时,对象的地址不是固定的,若我们使用指针去指向基类,那么每次一次运行都需要进行一次填写地址
在这里插入图片描述

菱形继承中的虚函数

class Object
{
	int value;
public:
	Object(int x = 0) :value(x) {}
	virtual void fun()
	{
		cout << "Object" << endl;
	}
	virtual void add()
	{
		cout << "Object::add" << endl;
	}
};
class Base : public Object
{
	int num;
public:
	Base(int x = 0) :num(x), Object(x + 10) 
	{}
	virtual void fun()
	{
		cout << "Base" << endl;
	}
};
class Test : public Object
{
	int sum;
public:
	Test(int x = 0) :sum(x), Object(x + 10) 
	{}
	virtual void fun()
	{
		cout << "Test" << endl;
	}
	virtual void add()
	{
		cout << "Test::add" << endl;
	}
};
class Det :public Base, public Test
{
private:
	int total;
public:
	Det(int x = 0) :total(x), Base(x + 10), Test(x + 20), Object(x + 30)
	{}
	virtual void fun()
	{
		cout << "Det" << endl;
	}
	virtual void add()
	{
		cout << "Det::add" << endl;
	}
};

int main()
{
	Det d(0);
	Object* opa = (Base*)&d; //这两处的d地址是不同的
	Object* opb = (Test*)&d;

	//Object* op = &d;           error
	//Object* op = (Object*)&d;	 error
	//d中包含两个Object地址,并不清楚指向哪一个
	
	opa->add();
	opa->fun();
	opb->add();
	opb->fun();

	return 0;
}

在这里插入图片描述
当我们菱形继承,需要对两个类的两个虚函数表进行继承

Object* opa = (Base*)&d; 
Object* opb = (Test*)&d;
//Object* op = &d;           error
//Object* op = (Object*)&d;	 error

在这里由于两个类的虚函数表不同,其中opa与opb分别获得的地址也不同,并且直接对Object 地址获取是错误的,因为子对象中有两个Object

那么是如何明确到底是继承来自哪一个对象的虚表

可以看出,opa指的是Base里面的Object对象,而opb指的是Test中的Object对象,我们Base对象指的是由Base对象继承而来的虚表,Test对象指的是由Test对象继承而来的虚表,我们会以某一个虚函数表为主,虚函数表2去调用为主的虚函数表1,通过虚函数表1去调动真实的函数地址

也就是说虚函数表1指向真实的地址,而虚函数表2指向的实际是调节器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值