1.C++继承关于子类的默认函数的写法
2.分析菱形继承的问题
3.剖析虚继承是怎么解决二义性和数据冗余的。
———————————————————————————————————————————————————
1.C++继承关于子类的默认函数的写法
构造原则如下:
a. 如果子类没有定义构造方法,则调用父类的无参数的构造方法。
b. 如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类的构造方法,然后执行自己的构造方法。
c. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数。
d. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数。
e. 在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。
f. 如果子类调用父类带参数的构造方法,需要用父类的构造函数.
例:
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person(char* name = "nini")
:_name(name)
{
cout<<"Person()"<<endl;
}
Person(const Person& p)
:_name(p._name)
{
cout<<"Person(const Person& p)"<<endl;
}
Person& operator=(const Person& p)
{
cout<<"operator = "<<endl;
if(this != &p)
{
_name = p._name;
}
return *this;
}
~Person()
{
cout<<"~Person"<<endl;
}
protected:
string _name;
};
class Student : public Person
{
public:
Student(char* name = "coco",int id = 0)
:Person(name) //这里调用基类的构造函数,来初始化_name,也可以不写,则默认调用
,_id(id) //基类的无参构造函数,一般都是写上。(不写无法给对象定义新的_name)
{
cout<<"Student()"<<endl;
}
Student(const Student& s)
:Person(s) //将Student的对象s的引用传过去拷贝_name,用了切片的方法
,_id(s._id) //如果这里不调基类的拷贝构造,则会默认调用基类的无参构造函数来对_name赋值
{
cout<<"Student(const Student& s)"<<endl;
}
Student& operator=(const Student& s)
{
cout<<"opertor="<<endl;
if(this != &s)
{
Person::operator =(s); //也用了切片给_name赋值,相当于*this.person::operator=(s)
}
return *this;
}
~Student() //不需要合并析构函数,因为基类的需要析构的对象在结束其作用周期时会自动调用
{ //基类的析构函数,所以如果合并的话,会调用两次基类的析构函数,造成不必要的麻烦
cout<<"~Student"<<endl;
}
protected:
int _id;
};
int main()
{
char *name = "abc";
Student s(name,3);
Student s1(s);
return 0;
}
———————————————————————————————————————————————————
2.分析菱形继承的问题
菱形继承是建立在多继承的基础上的。什么是多继承。
1.单继承-一个子类只有一个直接父类时称这个继承关系为单继承
2.多继承-一个子类有两个或以上直接父类时称这个继承关系为多继承
如图
菱形继承:也称多边形继承
如图
菱形继承即多个类继承了同一个公共基类,而这些派生类又同时被一个类继承
如下代码:
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 = "aaaaaaa";
return 0;
}
这个代码会报错,对“_name”的访问不明确。造成二义性
而且会有_name的冗余。
解决二义性的方法很简单,就是在_name前标明域,如a.Student::_name,则访问的是A中的_name,
可是每次使用时都要加,显得很麻烦,而且并没有解决冗余的问题。
所以C++内部提供了一个解决方法——虚继承
虚继承:在继承是加上关键字virtual 如class Assissant:virtual public Student
所以上面的代码就在Student类和 Teacher类继承时多加了个 virtual就解决了二义性和冗余的问题
———————————————————————————————————————————————————
3.剖析虚继承是怎么解决二义性和数据冗余的。
用图来说明