模板继承
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指向的实际是调节器