【C++学习笔记二】C++继承

继承

继承允许我们一句另一个类来定义一个类,这使得继承和维护一个程序变得更加容易,也达到了重用代码功能和提高执行效率的效果。

一般格式为:

class 派生类名 :访问修饰符 基类名{};

其中访问修饰符是public protected private中的一个,默认为private

派生类可以访问基类中所有的非私有成员,因此基类成员如果不想被派生类的成员访问,则应该在基类声明为private

一个派生类继承了所有的基类非私有方法,但是下列情况除外:

  • 基类的构造函数,析构函数和拷贝构造函数
  • 基类的重载运算符
  • 基类的友元函数

继承类型

  • 公有继承:基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护乘员胡安,基类的私有成员不能直接被派生类访问,但是可以通过基类的公有和保护方法来访问。
  • 保护继承:基类的公有和保护成员将成为派生类的保护成员
  • 私有继承:公有和保护成员将称为派生类的私有成员

多继承

一个子类可以有多个父类,继承了多个父类的特性,不同父类用逗号隔开。

class <派生类名>:<继承方式><基类名>,<继承方式>,<基类名><继承方式><基类名>,..
{};

虚继承

因为C++多继承的特性,当从两个方向继承到同一个类的时候就可能会出现拷贝了两份相同数据的问题,这个时候访问被拷贝多份的数据成员如果没有加名字空间编译器就会报错,因为不确定到底访问的是哪一份变量。为了解决这个问题,我们要使用虚继承从而实现只拷贝一份变量。需要注意的一点是,虚继承是指对多个类继承一个类的时候需要进行虚继承,这样就能解决一个类继承这多个类的时候出现的成员重复。

具体见样例:

class A{};
class B:virtual public A{};
class C:virtual public A{};
class D:public B,public C{};//注意对D来讲用virtual已经晚了,我们在上面个多个类继承A的时候用虚继承,这样有其他类继承B,C等的时候就不会出现问题。

继承机理

编译器先通过基类的构造函数创建一个基类的对象,然后再通过派生类的构造函数在后面加上派生类的成员,并进行初始化。基类中私有成员对派生类不可见,但是派生类对象可以通过父类提供的接口对父类中的对象进行访问。实际上派生类成员是含有基类中的所有的成员的。

对于相同名字的数据成员,通过基类方法改变的是基类的数据成员,通过派生类方法改变的是派生类数据成员。如果想要访问基类的(公有)成员可以使用名字空间。

可以由以下测试看出:


#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:int b;
};
class B :public A
{//int c[50];int d;
};int main()
{B a;printf("%d", sizeof(a));return 0;
}

运行结果:
在这里插入图片描述
显然派生类中含有基类的私有成员,只是不可以直接访问。

派生类的构造函数

详见另一篇文章:构造函数,作者讲的很好。

在每次派生类构造函数调用时,首先会调用父类的构造函数,然后再调用派生类的构造函数,最后先调用派生类的析构函数,最后调用父类的析构函数。

在每个派生类构造函数中,如果我们要使用父类的有参构造函数,则需要在函数头部调用。如果我们没有显式地调用父类的构造函数则编译器会自动在派生类构造函数开头调用基类的无参构造函数。(如果基类只有有参构造函数编译器会因为找不到无参构造函数而报错)。

显式调用的格式如下:

class A
{public:A(int x){}
};
class B:public A
{
public:
B():A(x)//只可以在这一个地方显式调用
{}
};

在其他地方显式调用都是没有意义的。(相当于创建了一个没有办法引用的父类)
见下例:


#include<iostream>
#include<cstdio>using namespace std;class A
{int a[100];
public:A(){printf("调用了无参构造函数\n");}~A(){printf("调用了析构函数\n");}A(int x){printf("调用了有参构造函数\n");a[0] = x;}int b;
};
class B :public A
{//int c[50];int d;
public:B(){A(5);printf("test\n");d = 0;}void Print(){printf("Hello world!\n");}
};int main()
{B* a=new B();printf("%d\n", sizeof(a));a->Print();delete a;return 0;
}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

处理大并发之二 对epoll的理解,epoll客户端服务端代码

http://blog.csdn.net/wzjking0929/article/details/51838370 序言&#xff1a; 该博客是一系列的博客&#xff0c;首先从最基础的epoll说起&#xff0c;然后研究libevent源码及使用方法&#xff0c;最后研究nginx和node.js&#xff0c;关于select,poll这里不做说明&#xff0c…

C++基类指针指向派生类(指针)

我们常用基类指针指向派生类对象来实现多态性。 私有继承不允许基类指针指向派生类 基类指针只能访问到基类中含有的公有成员。 当用基类指针指向派生类对象在动态分配堆上内存的时候&#xff0c;析构函数必须是虚函数! 成员如果是数据成员的话访问的是基类的版本&#xff…

C++虚继承中构造函数和析构函数顺序问题以及原理

多重继承的问题&#xff1a;多个类B,C,…继承同一个类A导致如果X继承了B,C,…那么在X中将还有多个A中成员的拷贝&#xff0c;如果想要访问A中的成员如果不加名字空间将会导致二义性&#xff0c;这种拷贝大多是没有实际意义的&#xff0c;为了避免这种空间浪费&#xff0c;C有虚…

一个简单的linux线程池

http://blog.csdn.net/wzjking0929/article/details/20312675 线程池&#xff1a;简单地说&#xff0c;线程池 就是预先创建好一批线程&#xff0c;方便、快速地处理收到的业务。比起传统的到来一个任务&#xff0c;即时创建一个线程来处理&#xff0c;节省了线程的创建和回收的…

【C++学习笔记三】C++多态、抽象(接口)

当类之间存在多种层次结构&#xff0c;并且类之间通过继承关联时就会用到多态。 虚函数在子类中的覆盖版本和该函数在基类中的原始版本必须有相同的函数签名、函数名、形参名、常属性。如果返回值为非类类型&#xff0c;则必须相同&#xff0c;如果是类类型A的指针或者引用&am…

C++重载和重写的条件以及重写后对基类函数的覆盖

重载&#xff1a;同一个类中名字相同&#xff0c;参数列表不同的方法构成重载函数&#xff0c;和返回值没有关系。这就意味着就算返回值不同&#xff0c;只要名字相同参数列表相同编译器还是会报错&#xff0c;觉得一函数被定义了两次。 重写&#xff1a;派生类中只要函数名字…

C++静态成员和静态方法

在类中&#xff0c;静态成员可以实现多个对象之间共享数据&#xff0c;同时保证了安全性。静态数据对该类的所有对象是公有的&#xff0c;存储一处供所有对象使用。 注意&#xff1a; 静态成员定义时需要在前面加上关键字static静态成员必须初始化且必须在类外进行&#xff0…

基于epoll的简单的http服务器

http://blog.csdn.net/fangjian1204/article/details/34415651 http服务器已经可以处理并发连接&#xff0c;支持多个客户端并发访问&#xff0c;每个连接可以持续读写数据&#xff0c;当然&#xff0c;这只是一个简单的学习例子&#xff0c;还有很多bug&#xff0c;发表出来只…

C++单例模式简单实现

有时候我们需要某个类只能被实例化一次&#xff0c;并且其他类都可以访问到这个类&#xff0c;就需要这种设计模式。 例如我们想要做个资源管理器&#xff0c;显然这个管理器只能有一个。 这种模式有很多实现方式&#xff0c;这里介绍最简单的一种&#xff0c;想要了解更多可…

Linux C++ 实现线程池

http://blog.csdn.net/qq_25425023/article/details/53914609 线程池中的线程&#xff0c;在任务队列为空的时候&#xff0c;等待任务的到来&#xff0c;任务队列中有任务时&#xff0c;则依次获取任务来执行&#xff0c;任务队列需要同步。 Linux线程同步有多种方法&#xff…

C++制表符

制表符的转义字符为\t&#xff0c;一般情况下长度为8个空格&#xff0c;这里的8个指的是从上一个字符串的开头开始算&#xff0c;往后数8个&#xff0c;不够的话就补空格。 如果前面的字符串的长度大于等于8个&#xff0c;例如前面字符串的长度为x,那么就会补(8-x%8)个空格 例…

C++派生类含有成员对象构造函数析构函数顺序

参考博客&#xff1a;传送门1 当类中含有对象成员时&#xff1a; 类的构造函数要包含对成员对象的初始化&#xff0c;如果构造函数的成员初始化列表没有包含对成员对象的初始化&#xff0c;系统会自动调用成员对象的无参构造函数。顺序上&#xff1a;先调用成员对象的构造函数…

c,c++中字符串处理函数strtok,strstr,strchr,strsub

http://blog.csdn.net/wangqing_12345/article/details/51760220 1&#xff0c;字符串切割函数 函数原型&#xff1a;char *strtok(char *s, char *delim); 函数功能&#xff1a;把字符串s按照字符串delim进行分割&#xff0c;然后返回分割的结果。 函数使用说&#xff1a; 1…

C++虚基类成员可见性

详见《CPrimer》[第五版]719页 如果继承路径上没有和虚基类成员重名的成员&#xff0c;则不存在二义性&#xff0c;因为我们仅能访问到虚基类成员。 当访问仅有一条继承路径上含有和虚基类成员重名的成员&#xff0c;也不存在二义性。派生类的成员的优先级比基类的成员高&…

链表逆序的原理及实例

http://blog.csdn.net/wangqing_12345/article/details/51757294 尾插法建立链表&#xff0c;带头结点设链表节点为typedef struct node {int data;struct node *next;}node_t, *pnode_t;要求将一带链表头List head的单向链表逆序。 分析&#xff1a; 1). 若链表为空或只有一个…

C++关于虚基类、构造函数、析构函数、成员对象的两个程序浅析

预备博客&#xff1a; C虚继承中构造函数和析构函数顺序问题以及原理 C派生类含有成员对象构造函数析构函数顺序 C虚基类成员可见性 程序一如下&#xff1a; #include<iostream> using namespace std; class A { public:A(int a) :x(a) { cout << "A const…

strtok函数及其实现

头文件&#xff1a;#include <string.h> 定义函数&#xff1a;char * strtok(char *s, const char *delim); 函数说明&#xff1a;strtok()用来将字符串分割成一个个片段。参数s 指向欲分割的字符串&#xff0c;参数delim 则为分割字符串&#xff0c;当 strtok()在参数s …

C++小型公司管理系统

项目要求&#xff1a; 编写一个程序实现小型公司的人员信息管理系统。该公司雇员&#xff08;employee&#xff09;包括经理&#xff08;manager&#xff09;&#xff0c;技术人员&#xff08;technician&#xff09;、销售员&#xff08;salesman&#xff09;和销售部经理&…

Linux网络编程“惊群”问题总结

http://www.cnblogs.com/Anker/p/7071849.html 1、前言 我从事Linux系统下网络开发将近4年了&#xff0c;经常还是遇到一些问题&#xff0c;只是知其然而不知其所以然&#xff0c;有时候和其他人交流&#xff0c;搞得非常尴尬。如今计算机都是多核了&#xff0c;网络编程框架也…

【Java学习笔记六】常用数据对象之String

字符串 在Java中系统定义了两种类型的字符串类&#xff1a;String和StringBuffer String类对象的值和长度都不能改变&#xff0c;称为常量字符串类&#xff0c;其中每个值称为常量字符串。 StringBuffer类对象的值和长度都可以改变&#xff0c;称为变量字符串类&#xff0c;其…