C++快速入门 (十三) 继承和多态
来源:互联网 发布:ie11不支持ie8的js 编辑:程序博客网 时间:2024/06/06 07:20
一,继承
(1). 继承的基本语法
继承是面向对象的基本特征之一。简单的继承示例如下:
class ExampleBase
{
private :
int x;
public :
ExampleBase( ) : x(0)
{
cout << "ExampleBase 类构造函数" << endl;
}
void SetX ( int n )
{
x = n ;
}
int GetNum()
{
return x;
}
};
class Example : public ExampleBase
{
private :
int y;
public :
Example( ):y(10)
{
cout << "Example 类构造函数" << endl;
}
int GetNum()
{
return y;
}
};
int _tmain (int argc, _TCHAR* argv [])
{
Example ex;
cout << ex.GetNum() << endl;
return 0;
};
// return:
// ExampleBase 类构造函数
// Example 类构造函数
// Example 类函数
// 10
总结:
- 创建派生类实例时,构造函数调用从最底层基类开始直至当前类。清理对象时顺序相反。
- 基类的访问修饰符对派生类依然有效。如 基类中的私有成员即使是派生类中依然无法访问。
- 派生类中只要有和基类同名的函数,即便是签名不同(参数或返回值不同),对于派生类对象,基类的同名函数将会被隐藏(和重载不同)。
你可以在派生类中通过作用域操作符调用基类的函数
Base ::GetNum();
(2). protected 修饰符
声明为 protected 的成员可以让从其派生的类访问。而在其他地方和声明为 private 一样外界无法访问(可参见下节示例)。
(3). 派生类中显式调用基类的构造函数
当基类中存在多个构造函数时,就有可能需要在派生类中调用指定的基类构造函数。方法如下:
class ExampleBase
{
protected :
int x;
public :
ExampleBase( ) : x(0)
{
cout << "ExampleBase 类无参数 构造函数" << endl;
}
ExampleBase(int n ) : x( n )
{
cout << "ExampleBase 类有参数 构造函数" << endl;
}
void SetX ( int n )
{
cout << "ExampleBase 类函数" << endl;
x = n ;
}
int GetNum()
{
return x;
}
};
class Example : public ExampleBase
{
private :
int y;
public :
Example( ):y(10),ExampleBase (15)
{
cout << "Example 类构造函数" << endl;
}
int GetNum()
{
cout << "Example 类函数" << endl;
return y;
}
int SumXy()
{
return x + y;
}
};
(4). 多重继承
C++中允许多重继承,既 一个类可以有多个基类,
class A
{
protected :
int x;
public :
A(): x(1)
{
cout << "A 类构造函数" << endl;
}
};
class B
{
protected :
int y;
public :
B(): y(2)
{
cout << "B 类构造函数" << endl;
}
};
class C
{
protected :
int z;
public :
C(): z(3)
{
cout << "C 类构造函数" << endl;
}
};
class Example : public A , public B, public C
{
public :
Example( )
{
cout << "Example 类构造函数" << endl;
}
int SumXyz()
{
return x + y + z;
}
};
int _tmain (int argc, _TCHAR* argv [])
{
Example ex;
cout << ex.SumXyz();
};
//return:
//A 类构造函数
//B 类构造函数
//C 类构造函数
//Example 类构造函数
//6
后边还会继续讨论多重继承。
二,多态
(1). 多态的基本理念
多态就是 可以用基类对象表示其派生类对象,在调用该对象上的函数时能正确调用派生类对象的相应函数(动态绑定)的一种能力。
典型的应用场景如: 某个函数的形参为基类类型(指针或引用),当调用时可以为其传入该基类的派生类并能正确调用。很显然一般的函数覆盖是实现不了动态绑定的,于是 C++引入了虚函数来完成动态绑定。
(2). 虚函数 virtual
C++中使用关键字 virtual 声明虚函数,
class Base
{
public :
virtual void ShowInfo()
{
cout << "is Base class" << endl;
}
};
class ExampleOne : public Base
{
public :
void ShowInfo()
{
cout << "is ExampleOne class" << endl;
}
};
class ExampleTwo : public Base
{
public :
void ShowInfo(int x)
{
cout << "is ExampleTwo class" << endl;
}
};
int _tmain (int argc, _TCHAR* argv [])
{
Base *b = new ExampleOne ;
b->ShowInfo();
Base *b2 = new ExampleTwo ;
b2->ShowInfo();
}
//return:
//is ExampleOne class
//is Base class
总结:
- 只有虚函数才具有多态(动态绑定)性。
- 只有派生类函数和基类中的虚函数签名完全相同时才会具有多态性,
- 用于覆盖基类虚函数的派生类函数也可以声明为虚函数。
- 析构函数也可以为多态的,所以一般的基类析构函数应为虚函数。
- 构造函数或析构函数中调用虚函数时,将只会调用其类型上的版本。
顺便提一句。即便是已经实现了动态绑定,也可以用如下语法显式的指定应该调用哪个类的函数
b->Base::ShowInfo();
(3). 纯虚函数
在虚函数后加 "= 0" 时,该虚函数就为纯虚函数。因为纯虚函数没有方法体自然就没法调用执行。这样的类是不完全的,所以拥有纯虚函数的类会变成了抽象类(不能被实例化的类)。
class Base
{
public :
virtual void ShowInfo() = 0;
};
当一个类继承自抽象类并且未覆盖其纯虚函数时,该类也会变成抽象类(显而易见)。
(4). 虚继承
当一个派生类间接继承多个相同基类时,该基类会在内存中有多个副本。
class Base
{
public :
int num;
};
class MidOne : public Base { };
class MidTwo : public Base { };
class Example : public MidOne , public MidTwo { };
int _tmain (int argc, _TCHAR* argv [])
{
Example *ex = new Example ;
cout << ex->num;
// error C2385: 对“num”的访问不明确, 因为有多个 Base的副本
}
可以通过 继承时添加 修饰符 virtual ,使内存只存储一个该基类的副本。
(5). 动态绑定原理
当类中有虚函数时(动态绑定基础),会生成一个保存该类所有虚函数(包括继承来未被覆盖的)地址的虚表(vtable),然后用一个指针(vptr)指向虚表,并将(大多数情况)该指针放在类的首地址。当将派生对象赋给基类对象时实际只是改变了基类对象的引用(指向派生类对象地址),这样就可以调用正确的虚函数,从而实现动态绑定。
class Base
{
public :
virtual void ShowInfo()
{
cout << "is Base" << endl;
}
virtual void Say()
{
cout << "is Base say" << endl;
}
};
class Example : virtual public Base
{
public :
virtual void ShowInfo()
{
cout << "is Example" << endl;
}
};
typedef void (*py)();
int _tmain (int argc, _TCHAR* argv [])
{
Base *b = new Example ;
void* vptr = ( void *)*(unsigned long*)b;
unsigned char *p = (unsigned char *)vptr;
p += sizeof( void *) * 0;
py vtable = ( py ) (void *)*(unsigned long *)p;
vtable();
p += sizeof( void *) * 1;
py vtable2 = ( py ) (void *)*(unsigned long *)p;
vtable2();
}
//return:
// is Example
// is Base say
三,动态绑定对象切割
(1). 切割
在某种情况下即便当前基类是一个指向派生类的引用(多态),也会将其转换为真正的基类,而派生类部分将被切掉。
(2). 值类型形参
当形参为值类型时,动态绑定类型将被切割,转换为纯基类类型。
class Base
{
public :
virtual void ShowInfo()
{
cout << "is Base" << endl;
}
};
class Example : virtual public Base
{
public :
virtual void ShowInfo()
{
cout << "is Example" << endl;
}
};
void Test ( Base b )
{
b.ShowInfo();
}
int _tmain (int argc, _TCHAR* argv [])
{
Base *ex = new Example ;
Test(*ex);
}
//return:
//is Base
(3). 容器和数组
当将动态绑定的类型存入容器(对象而非指针)时,也会被切割,转换为纯基类类型。
int _tmain (int argc, _TCHAR* argv [])
{
Base *ex = new Example ;
Base baseArray[3] = {};
baseArray[0] = *ex;
baseArray[0].ShowInfo();
Base *ex2 = new Example ;
Vector< Base > vr;
vr.push_back(*ex2);
vr[0].ShowInfo();
}
//return:
// is Base
// is Base
-
<原创文章 转载请注明出处 http://blog.csdn.net/meiwm 谢谢>
作者:meiwm
出处:http://blog.csdn.net/meiwm
本文为原创,本文版权归作者所有。欢迎转载,但请务必保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。
-
- C++快速入门 (十三) 继承和多态
- C继承和多态
- OC入门-继承和多态
- 快速入门C++ 11(虚继承、错误处理和调试)
- 【C++】继承和多态之——菱形继承
- C中的继承和多态
- 【转帖】C继承和多态
- C#中的接口和继承多态
- 继承和多态理解(C#)
- C语言实现继承和多态
- C中的继承和多态
- C#—继承和多态
- C语言实现继承和多态
- C语言实现继承和多态
- C语言实现继承和多态
- C++[语法]公有继承和多态
- C中的继承和多态
- C中的继承和多态
- fatal error lnk181 cannot open input file "..............\xx.lib"
- 用ddclient实现顶级域名动态解析
- android设备上视频只有声音没有图像
- SSH架构jar包
- [IOS]视图切换 JASidePanels (类似path2.0或者facebook系统设置,切换效果 )
- C++快速入门 (十三) 继承和多态
- 数据库建立索引的原则
- Sub-process returned an error code 的解决办法
- GIT 的使用方法详解
- 我的项目之RBAC
- 分页查询
- Ask Maclean
- chrome 硬件渲染
- Python正则表达式指南