每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)

Posted 赏一杯茶:

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)相关的知识,希望对你有一定的参考价值。

  1. 重载父类派生类成员函数
    看如下代码,判断输出结果:
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”。

切不能被参数类型迷惑,记住父类成员函数与派生类成员函数构成重载时,派生类中会将父类的进行隐藏;父类指针或引用调用派生类对象时,具有切片功能。

  1. 多态
    看如下代码,判断输出结果:
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

谨记构成虚函数重写的条件

  1. 函数名参数类型个数均相同
  2. 父类中该函数必须有virtual修饰
  1. 虚继承
    看如下代码:
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的继承顺序

  1. 理解多态的动态绑定
    看一段代码:
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”。

  1. 动态绑定:运行时绑定
  2. 静态绑定:编译时就已经确定

以上是关于每日一练---- 3.07 3.08 3.09oj总结(继承重载多态动态与静态绑定)的主要内容,如果未能解决你的问题,请参考以下文章

每日一练----1.18 oj总结

每日一练----1.18 oj总结

每日一练----1.22 oj总结

每日一练----1.22 oj总结

每日一练----1.22 oj总结

每日一练----1.21 oj总结