單繼承
一個子類只有一個直接父類時稱這個繼承關係爲單繼承。
class Person
{
public:
void setinfo(int _age, const char *_name)
{
age = _age;
name = _name;
}
protected:
int age;
public:
string name;
};
class Student:public Person
{
public:
void setinfo(int _age, const char *_name, int _num)
{
Person::setinfo(_age, _name);
num = _num;
}
protected:
int num;
};
多繼承
一個子類有兩個或以上直接父類時稱這個繼承關係爲多繼承
class Student
{
protected :
int _num ;
string _name;
};
class Teacher : public Person
{
protected :
int _id ;
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ;
};
菱形繼承
菱形繼承就是對單繼承和多繼承的一個組合
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 ; // 主修課程
};
Student 和Teacher類是對Person類的單繼承,而Assistant類則是多繼承前兩者。
lass A
{
public:
int _a;
};
class B1:public A
{
public:
int _b;
};
class B2 :public A
{
public:
int _c;
};
class D :public B1, public B2
{
public:
int _d;
};
void test()
{
D d;
//d._a= 0;
d._b = 1;
d._c = 2;
d._d = 3;
}
int main()
{
test();
return 0;
}
但是由派生類模型我們可以看到,Assistant類中有兩個Person成員,在對象d的內存中也可以看到由兩個隨機值,這就存在二義性和數據冗餘的問題。
爲了解決菱形繼承中的二義性問題,我們引入了虛擬繼承。
class A
{
public:
int _a;
};
class B:virtual public A
{
public:
int _b;
};
void test()
{
B b;
b._a = 1;
b._b = 2;
}
int main()
{
test();
return 0;
}
從我們學習到的普通繼承知識,我們知道,如果是普通繼承的話,派生類對象d的大小應該爲8,因爲只有基類的成員變量_a和派生類自己的的成員_b,
並且和普通繼承不同,普通繼承派生類模型是基類在上,派生類在下,這裏是基類在下,派生類在上,並且在前面多了四個字節的內容,我們把這個類容當作地址再次
在這個多了兩個數,一個0一個8,我們在上面的代碼中在派生類中添加一個變量,_b,
lass B:virtual public A
{
public:
int _b;
int _b1;
};
從這裏我們可以看出,這個0是派生類對於自己的偏移量,因爲不管你類的內容怎麼改變這個0都不變,但是下面那個數字會隨着你派生類的大小而改變,下面的數是派生類和基類的偏移量,我們把他叫做偏移量表格,
所以,在虛擬繼承中,有一個指向偏移量表格的偏移地址,
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class B
{
public:
int _b;
};
class C1 :virtual public B
{
public:
int _c1;
};
class C2 :virtual public B
{
public:
int _c2;
};
class D :public C1, public C2
{
public:
int _d;
};
void Test1()
{
D d1;
cout << sizeof(D) << endl;
d1._c1 = 0;
d1._c2 = 1;
d1._d = 2;
d1._b = 3;
}
int main()
{
Test1();
system("pause");
return 0;
}
這裏有兩個偏移地址,
0x012bcb04
0x012bcf70
一開始運行程序時遇到的_b不明確的問題也沒有出現了。