c++基础06

继承的引出

网页有很多公共部分

导致实现时候有很多重复的代码

引出继承,基类(父类) 公共网页

具体子类 实现不同的内容

语法:class 子类 :继承方式 父类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

using namespace std;
class
{
private:

public:
BasePage(/* args */){}
~BasePage(){}
void header()
{
cout<<"公共头部"<<endl;
}
void footer()
{
cout<<"公共底部"<<endl;
}
void left()
{
cout<<"左侧列表"<<endl;
}
};

class News :public BasePage
{
private:

public:
News (/* args */){}
~News (){}
void content()
{
cout<<"新闻播放"<<endl;
}
};

class YULE :public BasePage
{
public:
YULE(){}
~YULE(){}
void content()
{
cout<<"娱乐项目"<<endl;
}
};


void test()
{
cout<<"新闻网页内容: "<<endl;
News news;
news.header();
news.footer();
news.left();
news.content();

cout<<"娱乐网页内容: "<<endl;
YULE yl;
yl.header();
yl.footer();
yl.left();
yl.content();
}
int main(void)
{
test();
return 0;
}

继承方式

不管是公共继承、保护继承还是私有继承,基类中的私有属性,都不可以继承下去

公有继承:父类中的public在子类中是public,父类中的protected在子类中还是protected

保护继承:父类中的public在子类中是protected,父类中的protected在子类中还是protected

私有继承:父类中的public在子类中是private,父类中的protected在子类中还是private

继承中的对象模型

子类会继承父类中所有的内容,包括了私有属性

只是我们访问不到,被编译器隐藏了

继承中的构造和析构

子类创建对象时,先调用父类的构造,然后调用自身的构造,析构顺序相反

子类不会继承父类的构造函数和析构函数

如果父类中没有合适的默认构造,那么子类可以利用初始化列表的方式显示的调用父类的其他构造

继承中的同名处理

成员属性:直接调用先调用子类,如果想调用父类的,需要作用域

成员函数:直接调用先调用子类,父类的所有版本(如默认和有参)都会被隐藏,除非加上作用域运算符去调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

using namespace std;

class Base
{
private:

public:
Base(/* args */)
{
m_A = 100;
}

void fun()
{
cout<<"Base fun调用"<<endl;
}

void fun(int a)
{
cout<<"Base fun(int a)调用"<<endl;
}
int m_A;
};


class Son:public Base
{
private:

public:
Son()
{
m_A = 200;
}

void fun()
{
cout<<"Son fun调用"<<endl;
}
int m_A;
};


void test()
{
Son s1;
cout<<s1.m_A<<endl;

cout<<s1.Base::m_A<<endl;

s1.fun();
//s1.fun(10);//无法调用
s1.Base::fun(10);
s1.Base::fun();
}

int main(void)
{
test();
return 0;
}

继承中静态成员的处理

类似非静态成员函数、属性的处理

如果想访问父类中的成员,加作用域即可

多继承的概念以及问题

class A : public B1, puublic B2 …;

引发二义性问题,要通过作用域解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

using namespace std;

class Base1
{
private:

public:
Base1(/* args */)
{
m_A = 10;
}
~Base1() {}

int m_A;
};

class Base2
{
private:

public:
Base2(/* args */)
{
m_A = 20;
}
~Base2() {}
int m_B;
int m_A;
};

class Son:public Base1, public Base2
{
private:

public:
Son(/* args */) {}
~Son() {}

int m_C;
int m_D;
};
void test()
{
cout<<sizeof(Son)<<endl;

Son s1;
// s1.m_A; //二义性
cout<<s1.Base1::m_A<<endl;
cout<<s1.Base2::m_A<<endl;
}
int main(void)
{
test();
return 0;
}

菱形继承问题以及解决

解决问题利用虚基类

vbptr 虚基类指针

指向一张虚基类表

通过表找到偏移量

找到共有的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

using namespace std;

class Animal
{
private:

public:
Animal(/* args */) {}
~Animal() {}
int m_Age;
};
//虚基类
class Sheep: virtual public Animal
{
private:

public:
Sheep(/* args */) {}
~Sheep() {}
};
//虚基类
class Tuo: virtual public Animal
{
private:

public:
Tuo(/* args */) {}
~Tuo() {}
};

class SheepTuo: public Sheep, public Tuo
{
private:
/* data */
public:
SheepTuo(/* args */) {}
~SheepTuo() {}
};
void test()
{
SheepTuo st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 20;
st.m_Age = 100;
cout<<st.Sheep::m_Age<<endl;
cout<<st.Tuo::m_Age<<endl;
cout<<st.m_Age<<endl;//可以直接访问,没有了二义性,只有一份m_Age

cout<<*(int *)((int *)*(int *)&st + 1)<<endl;


}
int main(void)
{

test();
//system("pause");
return 0;
}