C++继承(下)

1.继承和友元 

友元函数不能继承,换句话说父类的友元不能访问子类私有和保护成员。(不作为重点)

class Student;//提前声明,因为友元关系不能被继承,那么Person
			  //类里的友元函数中的Student找不到对应的类(程序是从上而下寻找的)

class Person
{
public:
	friend void Test(const Person& p, const Student& s);

protected:
	string _name;
};

class Student : public Person
{
public:
	friend void Test(const Person& p, const Student& s);
protected:
	string _id;
};

void Test(const Person& p, const Student& s)
{
	cout << p._name << endl;
	cout << s._id << endl;//“Student::_id”: 无法访问 protected 成员(在“Student”类中声明)
	//如果想要解决这种问题,把Test也变成Student的友元即可
}

int main()
{
	Person person;
	Student stu;

	Test(person, stu);

    return 0;
}

2.继承与静态成员 

父类定义类static成员,那么整个继承体系里只有一个这样的成员无论派生出多少个子类,都只有一个static成员实例

class Person
{
public:
	string _name;
	static string _sex;
};

string Person::_sex = "女";//静态成员变量在类外进行声明

class Student : public Person
{
protected:
	string _id;
};


int main()
{
	Person person;
	Student stu;

	cout << &person._sex << endl;
	cout << &stu._sex << endl;//地址一样,均为00007FF7DCA45440

	//公有情况下,父子类指定类域都可以访问静态成员
	cout << Person::_sex << endl;
	cout << Student::_sex << endl;
}

3.多继承及其菱形继承问题 

3.1继承模型

单继承一个父类只有一个直接父类时称这个继承关系为单继承

多继承一个父类有两个或两个以上继承时称这个继承为多继承,多继承对象在内存中的模型是:先继承的父类在前面,后继承的父类在后面,子类成员房贷最后面。

菱形继承:菱形继承是多继承的一种特殊情况。菱形继承有数据冗余和二义性的问题,在D的对象中A成员会有两份。实践中不建议设计出菱形继承这种模型。

class Person
{
public:
	string _name; // 姓名
};

class Student : public Person
{
protected:
	int _num; //学号
};

class Teacher : public Person
{
protected:
	int _id; // 职⼯编号
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	Assistant a;
	//a._name = "李三";//报错,因为这是个菱形继承,会有二义性问题,编译器并不知道_name所指的是哪一个

	// 需要显⽰指定访问哪个基类的成员可以解决二义性问题,但是数据冗余问题⽆法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";

	return 0;
}

3.2虚继承

为了解决菱形继承所存在的问题,C++增加了virtual关键字,也就是虚继承。

注意:哪个类产生数据冗余和二义性,继承那个类的时候加virtual

class Person
{
public:
	string _name; // 姓名
};

class Student : virtual public Person
{
protected:
	int _num; //学号
};

class Teacher : virtual public Person
{
protected:
	int _id; // 职⼯编号
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

3.3 多继承中指针偏移问题

看下面一道题:

class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;
return 0;
}

p1、p2和p3是什么关系?

首先,可以从代码看出是一个多继承问题,Derive继承Base1和Base2。其次,根据基类指针或引用指向的是派生类中切出来的基类那部分以及先继承的在前面可以看出,p1和p3指向同一处地方。最后,用画图来解释一下:

4.继承和组合

  • public继承是is-a关系。
  • 组合是has-a关系。

  • 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的内部细节对派生类可见。继承一定程度破坏了基类的封装,基类的改变,对派生类有很大的影响。派生类和基类间的依赖关系很强,耦合度高。
  • 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse), 因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。
  • 优先使用组合,而不是继承。实际尽量多去用组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就用继承,另外要实现多态,也必须要继承。类之间的关系既适合用继承(is-a)也适合组合(has-a),就用组合。

over~ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值