每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)
Posted 赏一杯茶:
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)相关的知识,希望对你有一定的参考价值。
- 重载父类派生类成员函数
看如下代码,判断输出结果:
class A
public:
void test(int a) cout << "1";
;
class B :public A
public:
void test(float b) cout << "2";
;
int main()
A* a = new A;
B* b = new B;
a = b;
b->test(2);
a->test(1.1);
return 0;
下面对这段代码解读:
这里考的是函数重载,在类B中,隐藏了继承下类A的成员函数,用类B的指针或引用去调用test函数,打印的结果都是“2”。当用类A的指针或者引用指向类B时,C++中有一种切片功能,当父类指针或引用指向派生类时,会切掉派生类的部分,保留父类的部分。故a调用test时打印的结果是“1”。最后打印的结果是“21”。
切不能被参数类型迷惑,记住父类成员函数与派生类成员函数构成重载时,派生类中会将父类的进行隐藏;父类指针或引用调用派生类对象时,具有切片功能。
- 多态
看如下代码,判断输出结果:
class Base
public:
Base(int j) : i(j)
virtual~Base()
void func1()
i *= 10;
func2();
int getValue()
return i;
protected:
virtual void func2()
i++;
protected:
int i;
;
class Child : public Base
public:
Child(int j) : Base(j)
void func1()
i *= 100;
func2();
protected:
void func2()
i += 2;
;
int main()
Base* pb = new Child(1);
pb->func1();
cout << pb->getValue() << endl; delete pb;
首先在创建Child对象时,将父类Base中的i赋值为了1。用父类的指针去调用func1,而func1不是虚函数,所以构成重载,又根据切片功能,所以调用Base的fun1函数,接着调用func2函数,而func2函数是虚函数,且在派生类中完成了重写覆盖,故调用派生类Child的func2函数,i的值为12
谨记构成虚函数重写的条件
- 函数名参数类型个数均相同
- 父类中该函数必须有virtual修饰
- 虚继承
看如下代码:
class A
public:
A(const char* s) cout << s << endl; ~A()
;
class B : virtual public A
public:
B(const char* s1, const char* s2) :A(s1) cout << s2 << endl;
;
class C : virtual public A
public:
C(const char* s1, const char* s2) :A(s1) cout << s2 << endl;
;
class D : public B, public C
public:
D(const char* s1, const char* s2, const char* s3, const char* s4) :B(s1, s2), C(s1, s3), A(s1) cout << s4 << endl;
;
int main()
D* p = new D("class A", "class B", "class C", "class D"); delete p; return 0;
在这里先大致解释一下虚继承:当出现这种菱形继承时,为了防止数据冗余,往往采用虚继承。意思就是当类D继承类B与类C时,D中只包括一份类A的数据,不会出现两份类A的数据,这就是虚继承。
弄清楚虚继承后,当构造D对象时,先从最最最基础的类A开始构造,而后按照B与C的继承先后顺序构造,即A->B->C->D
如果我们改变一下B与C的继承顺序
- 理解多态的动态绑定
看一段代码:
class A
public:
void foo() printf("foo");
A() bar();
protected:
virtual void bar() printf("bar");
;
class B :public A
public:
void foo() printf("b_foo");
protected:
void bar() printf("b_bar");
;
int main()
A* p = new B;
return 0;
分析代码: 首先构造出派生类B对象出来,此时调用B的构造函数与A的构造函数,A的构造函数中又调用函数bar() ,按照前面两题的思路函数bar()是虚函数且在派生类中完成了重写,所以调用B中的bar()会打印出“b_bar”,但是这是错误的,因为编译器在绑定虚函数时是动态绑定,此时类A正在实例化,类B还没有完成实例化,类B中的bar()函数自然没有完成重写,所以虚函数表中的指针仍是指向类A的bar(),所以打印“bar”。
- 动态绑定:运行时绑定
- 静态绑定:编译时就已经确定
以上是关于每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)的主要内容,如果未能解决你的问题,请参考以下文章