初识C++之继承
2016-04-11 17:30
791 查看
1、何为继承
C++中所谓继承,就是在一个已存在类的基础上创建一个新的类,新类获得已存在类的部分特性(为什么是部分特性,后面会讲到)。已存在类被称为基类(Base Class)或父类(Father Class),新建类被称为派生类(Derived Class)或子类(Son Class)。
![](http://img.blog.csdn.net/20160411012251215)
继承的声明形式:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
2、分类
继承在C++中有单继承与多继承的分类。
单继承:派生类有且只有一个基类
多继承:派生类两个或两个以上的基类
文字描述不过瘾,给出声明方法、模型及实例:
①简单的单继承声明方法、模型及实例:
class 派生类名:[继承方式] 基类名
{
派生类增加的特性;
}
![](http://img.blog.csdn.net/20160411002312924)
②简单的多继承声明方法、模型及实例:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
![](http://img.blog.csdn.net/20160411002330773)
3、继承方式
先来回忆一下继承的声明形式:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
其中,继承方式分为共有(public)、私有(private)、保护(protected)之分,不同的继承方式会产生不同的继承效果(class默认继承方式是私有,struct默认继承方式是公有,但最好还是显示给出继承方式,这样会使程序更加清晰)。
继承方式的区别:
public:基类的非私有成员在派生类中的访问属性不变,基类的私有属性在派生类中存在但不可见。
protected:基类的非私有成员都称为派生类中的保护成员,基类的私有属性在派生类中存在但不可见。
private:基类的非私有成员都称为派生类中的私有成员,基类的私有属性在派生类中存在但不可见。
以上就是为什么说只是基类的部分特性在派生类中可见。
输出结果:
![](http://img.blog.csdn.net/20160411131346604)
对以上输出结果分析:
①为什么ShowBase会被调用两次
ShowBase函数被调用了两次,是因为在Derived类中,继承有ShowBase函数,因为该函数在Base类中的属性是public,而且Derived类是以public方式继承自Base类的,所以该函数在Derived类中的属性仍为public,那么它就可以在类外被调用。
②为什么两个类的大小不同
从输出结果中很明显的看到,Base类的大小为12,Derived类的大小为2。Base类的大小为12很好理解,因为它里面只有三个成员变量,且都为int类型,但为什么Derived是24呢,这就要牵扯到了继承方式特性,不管继承方式是什么,基类的成员变量的访问限定符是什么,基类的成员变量在派生类中都是存在的,只是有可见与不可见之分。
当我把继承方式修改为protected和private时,程序编译出错:
![](http://img.blog.csdn.net/20160411133053564)
![](http://img.blog.csdn.net/20160411133129753)
这就印证了我们上述的继承方式的特性,因为protected继承方式会把Base类中public访问限定符的BaseShow函数在Derived类中降级为protected访问限定符,同样,private继承方式会把Base类中public访问限定符的BaseShow函数在Derived类中降级为private访问限定符,而protected访问限定符和private访问限定符修饰的内容在类外是不可见的,强行调用肯定会报错,所以这儿会出现错误。
继承方式的特性:
①基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
②不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
③使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
4、继承关系中构造函数和析构函数的调用
先给出一个例子来剖析:
![](http://img.blog.csdn.net/20160411135057217)
可以看到在派生类创建对象时,是先调用基类的构造函数,然后在代用自己的构造函数,对于析构函数就很好解释了,可以理解为栈的特性,先进后出。
5、继承关系的作用域
在C++的继承体系中,基类和派生类是属于两个不同作用域。当基类和派生类中有同名成员时,派生类成员将屏蔽基类对成员的直接访问(在派生类成员函数中,可以使用 基类名::基类成员来访问基类的同名成员),这就是所谓的同名隐藏,在派生类中的同名成员称为对基类同名成员的重定义。当然,实际中在继承体系里面最好不要定义同名的成员。
注意:因为基类和派生类是属于两个不同作用域,所以两个类中的同名函数不会构成函数重载。
![](http://img.blog.csdn.net/20160411152623062)
根据上面例子的输出就可以看出来。
6、基类对象与派生类对象的赋值关系
①子类对象可以赋值给父类对象
输出结果:
![](http://img.blog.csdn.net/20160411155608386)
程序可以正常输出,但有些人可能会奇怪,为什么b里面存的是5、10、15,而不是4、5、6,其实原因很简单:
![](http://img.blog.csdn.net/20160411161042294)
②父类对象不能赋值给子类对象
当我把上例中的“b = d;”换成“d = b;”时,编译器会报错:
![](http://img.blog.csdn.net/20160411161340266)
还是像刚才那样分析:
![](http://img.blog.csdn.net/20160411162212950)
③父类的指针/引用可以指向子类对象,但是无法使用不存在于基类只存在于派生类的元素。
输出结果:
![](http://img.blog.csdn.net/20160411162530891)
上分析图:
![](http://img.blog.csdn.net/20160411164402389)
④子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
我把上例中的
换成
程序会报错:
![](http://img.blog.csdn.net/20160411164730687)
继续上图分析:
![](http://img.blog.csdn.net/20160411165836660)
7、友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
8、继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。
![](http://img.blog.csdn.net/20160411172833866)
可以看到两次输出都是10。
C++中所谓继承,就是在一个已存在类的基础上创建一个新的类,新类获得已存在类的部分特性(为什么是部分特性,后面会讲到)。已存在类被称为基类(Base Class)或父类(Father Class),新建类被称为派生类(Derived Class)或子类(Son Class)。
继承的声明形式:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
2、分类
继承在C++中有单继承与多继承的分类。
单继承:派生类有且只有一个基类
多继承:派生类两个或两个以上的基类
文字描述不过瘾,给出声明方法、模型及实例:
①简单的单继承声明方法、模型及实例:
class 派生类名:[继承方式] 基类名
{
派生类增加的特性;
}
class Base //父类/基类 { void Fun() { cout << "Base" << endl; } protected: int data; }; class Derived1: public Base //子类1/派生类1 { void Fun() { cout << "Derived1" << endl; } private: int _data; }; class Derived2: public Base //子类2/派生类2 { void Fun() { cout << "Derived2" << endl; } private: int _data; };
②简单的多继承声明方法、模型及实例:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
class Base1 { void Fun() { cout << "Base" << endl; } protected: int data1; }; class Base2 { void Fun() { cout << "Base" << endl; } protected: int data2; }; class Derived: public Base1, public Base2 { void Fun() { cout << "Derived" << endl; } private: int _data; };
3、继承方式
先来回忆一下继承的声明形式:
class 派生类名:[继承方式] 基类列表
{
派生类增加的特性;
}
其中,继承方式分为共有(public)、私有(private)、保护(protected)之分,不同的继承方式会产生不同的继承效果(class默认继承方式是私有,struct默认继承方式是公有,但最好还是显示给出继承方式,这样会使程序更加清晰)。
继承方式的区别:
public:基类的非私有成员在派生类中的访问属性不变,基类的私有属性在派生类中存在但不可见。
protected:基类的非私有成员都称为派生类中的保护成员,基类的私有属性在派生类中存在但不可见。
private:基类的非私有成员都称为派生类中的私有成员,基类的私有属性在派生类中存在但不可见。
以上就是为什么说只是基类的部分特性在派生类中可见。
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base() {} ~Base() {} void ShowBase() { cout << "ShowBase" << endl; cout << "pri = " << pri << endl; cout << "pro = " << pro << endl; cout << "pub = " << pub << endl; } private: int pri; protected: int pro; public: int pub; }; class Derived :public Base { public: Derived() {} ~Derived() {} void ShowDerived() { cout << "ShowDerived" << endl; cout << "_pri = " << _pri << endl; cout << "_pro = " << _pro << endl; cout << "_pub = " << _pub << endl; } private: int _pri; protected: int _pro; public: int _pub; }; int main() { Base b; Derived d; b.ShowBase(); d.ShowBase(); d.ShowDerived(); cout << sizeof(Base) << endl; cout << sizeof(Derived) << endl; return 0; }
输出结果:
对以上输出结果分析:
①为什么ShowBase会被调用两次
ShowBase函数被调用了两次,是因为在Derived类中,继承有ShowBase函数,因为该函数在Base类中的属性是public,而且Derived类是以public方式继承自Base类的,所以该函数在Derived类中的属性仍为public,那么它就可以在类外被调用。
②为什么两个类的大小不同
从输出结果中很明显的看到,Base类的大小为12,Derived类的大小为2。Base类的大小为12很好理解,因为它里面只有三个成员变量,且都为int类型,但为什么Derived是24呢,这就要牵扯到了继承方式特性,不管继承方式是什么,基类的成员变量的访问限定符是什么,基类的成员变量在派生类中都是存在的,只是有可见与不可见之分。
当我把继承方式修改为protected和private时,程序编译出错:
这就印证了我们上述的继承方式的特性,因为protected继承方式会把Base类中public访问限定符的BaseShow函数在Derived类中降级为protected访问限定符,同样,private继承方式会把Base类中public访问限定符的BaseShow函数在Derived类中降级为private访问限定符,而protected访问限定符和private访问限定符修饰的内容在类外是不可见的,强行调用肯定会报错,所以这儿会出现错误。
继承方式的特性:
①基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
②不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
③使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
4、继承关系中构造函数和析构函数的调用
先给出一个例子来剖析:
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } private: int pri; protected: int pro; public: int pub; }; class Derived :protected Base { public: Derived() { cout << "Derived()" << endl; } ~Derived() { cout << "~Derived()" << endl; } private: int _pri; protected: int _pro; public: int _pub; }; int main() { Base b; Derived d; return 0; }
可以看到在派生类创建对象时,是先调用基类的构造函数,然后在代用自己的构造函数,对于析构函数就很好解释了,可以理解为栈的特性,先进后出。
5、继承关系的作用域
在C++的继承体系中,基类和派生类是属于两个不同作用域。当基类和派生类中有同名成员时,派生类成员将屏蔽基类对成员的直接访问(在派生类成员函数中,可以使用 基类名::基类成员来访问基类的同名成员),这就是所谓的同名隐藏,在派生类中的同名成员称为对基类同名成员的重定义。当然,实际中在继承体系里面最好不要定义同名的成员。
注意:因为基类和派生类是属于两个不同作用域,所以两个类中的同名函数不会构成函数重载。
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base(int _pub = 0, int _pri = 1, int _pro = 2) : pub(_pub) , pri(_pri) , pro(_pro) {} ~Base() {} void Display() { cout << "Base::Display" << endl; cout << "pub = " << pub << endl; cout << "pri = " << pri << endl; cout << "pro = " << pro << endl; } public: int pub; private: int pri; protected: int pro; }; class Derived: public Base { public: Derived(int _pub = 0, int _pri = 1, int _pro = 2) : pub(_pub) , pri(_pri) , pro(_pro) {} ~Derived() {} void Display() { cout << "Derived::Display" << endl; cout << "pub = " << pub << endl; cout << "pri = " << pri << endl; cout << "pro = " << pro << endl; } public: int pub; private: int pri; protected: int pro; }; int main() { Base b(1, 2, 3); Derived d(4, 5, 6); b.Display(); d.Display(); return 0; }
根据上面例子的输出就可以看出来。
6、基类对象与派生类对象的赋值关系
①子类对象可以赋值给父类对象
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base(int bpub = 5, int bpri = 10, int bpro = 15) : pub(bpub) , pri(bpri) , pro(bpro) {} ~Base() {} void Display() { cout << "Base::Display" << endl; cout << "pub = " << pub << endl; cout << "pri = " << pri << endl; cout << "pro = " << pro << endl; } public: int pub; private: int pri; protected: int pro; }; class Derived: public Base { public: Derived(int _dpub = 10, int _dpri = 20, int _dpro = 30) : _pub(_dpub) , _pri(_dpri) , _pro(_dpro) {} ~Derived() {} void Display() { cout << "Derived::Display" << endl; cout << "_pub = " << _pub << endl; cout << "_pri = " << _pri << endl; cout << "_pro = " << _pro << endl; } public: int _pub; private: int _pri; protected: int _pro; }; int main() { Base b(1, 2, 3); Derived d(4, 5, 6); b = d; b.Display(); d.Display(); return 0; }
输出结果:
程序可以正常输出,但有些人可能会奇怪,为什么b里面存的是5、10、15,而不是4、5、6,其实原因很简单:
②父类对象不能赋值给子类对象
当我把上例中的“b = d;”换成“d = b;”时,编译器会报错:
还是像刚才那样分析:
③父类的指针/引用可以指向子类对象,但是无法使用不存在于基类只存在于派生类的元素。
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base(int bpub = 5, int bpri = 10, int bpro = 15) : pub(bpub) , pri(bpri) , pro(bpro) {} ~Base() {} void Display() { cout << "Base::Display" << endl; cout << "pub = " << pub << endl; cout << "pri = " << pri << endl; cout << "pro = " << pro << endl; } public: int pub; private: int pri; protected: int pro; }; class Derived: public Base { public: Derived(int _dpub = 10, int _dpri = 20, int _dpro = 30) : _pub(_dpub) , _pri(_dpri) , _pro(_dpro) {} ~Derived() {} void Display() { cout << "Derived::Display" << endl; cout << "_pub = " << _pub << endl; cout << "_pri = " << _pri << endl; cout << "_pro = " << _pro << endl; } public: int _pub; private: int _pri; protected: int _pro; }; int main() { Derived d(4, 5, 6); Base *b = &d; b->Display(); return 0; }
输出结果:
上分析图:
④子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
我把上例中的
int main() { Derived d(4, 5, 6); Base *b = &d; b->Display(); return 0; }
换成
int main() { Base b(4, 5, 6); Derived *d = &b; d->Display(); return 0; }
程序会报错:
继续上图分析:
7、友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
8、继承与静态成员
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Base { public: Base(int bpub = 5, int bsta = 0, int bpri = 10, int bpro = 15) : pub(bpub) , pri(bpri) , pro(bpro) {} ~Base() {} void Display() { cout << "Base::Display" << endl; cout << "sta = " << sta << endl; } public: int pub; static int sta; private: int pri; protected: int pro; }; class Derived: public Base { public: Derived(int _dpub = 10, int _dpri = 20, int _dpro = 30) : _pub(_dpub) , _pri(_dpri) , _pro(_dpro) {} ~Derived() {} void Display() { cout << "Derived::Display" << endl; cout << "sta = " << sta << endl; } public: int _pub; private: int _pri; protected: int _pro; }; int Base::sta = 10; int main() { Base b; Derived d; b.Display(); d.Display(); return 0; }
可以看到两次输出都是10。
相关文章推荐
- C++基本语法-----vector和list
- 浅析c语言中的变量(局部变量,外部变量,静态变量,寄存器变量)
- 重新学习《C++Primer5》第1-5章
- 几种C++ std::string和std::wstring相互转换的转换方法(转)
- 一个C语言写的简单的单词识别程序附带VS性能分析结果
- C++ 虚函数
- C++ vector的用法小结
- c/c++中的条件编译实例
- c语言的printf一个小问题
- 【day0411 C++】顺序容器 STL deque类
- C++友元函数访问私有成员
- C语言结构和其他数据形式
- 快速排序算法C语言版
- c++作业3
- C++实验3—多分段函数求值
- 【python】 Windows下pip安装包报错:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat
- C++遍历所有IE浏览器,得到里面的所有元素
- C++递归创建多级目录
- c++获取当前系统时间并输出到文件中
- C++实验3-个人所得税计算器