1.尽管派生类中含有基类继承来的成员,但派生类初始化这部分变量需要调用基类的构造函数。

 class A
{
private:
int x;
virtual void f(){cout<<"A f"<<endl;}
public:
A(/* args */){x=;cout<<"A构造"<<endl;}
~A(){}
friend void p(const A& a){cout<<a.x;}
};
class B:A{
public:
void f() override {cout<<"B f"<<endl;}
operator A()const {}
};
int main()
{
B x;
system("pause");
return ;
}

2.如果基类定义了一个静态成员,则整个继承体系中只存在该成员的唯一定义。并且不论基类派生出多少派生类,该静态成员只存在唯一实例。

并且属性也一致。基类中某静态成员是public,派生类中也是public。如果基类中是private,那么派生类也无法调用该静态成员。

 /* 基类的静态成员 */

 #include<iostream>

 using namespace std;

 class base
{
public:
static int num; base()
{
num+=;
} ~base()
{
num-=;
}
}; // 基类定义的静态成员,被所有派生类共享
// 起到计数器的作用,自身还有所有派生类对象的个数
// 遵循私有 公有 保护的继承机制 访问不同
// 可以通过父类 子类对象访问 还可以通过父类 子类类名访问
int base::num = ;// 类的静态成员 class basenew : public base
{ }; class basenewx : public basenew
{ }; void main()
{
basenew *p = new basenew[]; base *p1 = new base[] basenewx *p2 = new basenewx[]; cout << p->num << endl;//
cout << p1->num << endl;//
cout << p2->num << endl;// cin.get();
}

3.如果不想让某个类被继承,在类名后加final关键字。

final除了可以修饰类外,还可以修饰成员函数。还可以指明某个基类的虚函数不能被其派生类版本覆盖,如下:

首先要明确覆盖(override)与重载(overload)的定义,区别出什么是覆盖和重载:

覆盖就是派生类中虚成员函数覆盖基类中同名且参数相同的成员函数。

 class A
{
public:
A(/* args */){}
virtual void f()final {}
virtual ~A(){}
};
class B:public A{
public:
void f(int x){}//重载(overload)
void f(){} //覆盖(override,非法,因为A中的f声明了final)
};

4.派生类对象是基类对象,派生类中包含有基类的成员。基类对象不是派生类对象,它不能包含派生类型的成员。

派生类可以向基类转化(仅限指针和引用),基类不能向派生类转化(毕竟派生类有多余的数据,基类没法自己生成)

如果用派生类对象为一个基类对象初始化或者赋值,只有其中的基类部分会被拷贝/移动/赋值,它的派生类部分会被忽略。

 class A
{
private:
int x;
public:
A(/* args */){x=;cout<<"A构造"<<endl;}
virtual ~A(){}
};
class B:public A{ };
int main()
{
A x;
B y;
A* p=&y;//正确,将基类指针指向派生类变量,派生类指针隐式转换为基类指针。
B* q=&x;//错误
system("pause");
return ;
}

5.动态绑定(即dynamic bninding)只有当我们通过指针或者引用调用虚函数时才会发生。

由于继承导致对象的指针和引用具有两种不同的类型:静态类型和动态类型。
静态类型:指针或者是引用声明时的类型。
动态类型:由实际指向的类型确定。

其中静态类型编译时就已经确定,动态类型只有到运行的时候才能知道。所以如果用普通类类型调用虚函数,编译时就会把要调用的虚函数版本确定下来。

 class A
{
public:
A(/* args */){}
virtual void f(){cout<<"基类的f"<<endl;}
virtual ~A(){}
};
class B:public A{
public:
void f(){cout<<"派生类的f"<<endl;}
};
void F(A& p){
p.f();
}
int main()
{
A x;
B y;
F(x);
F(y);
system("pause");
return ;
}

可以看到同一个函数F,因为调用不同类型实参,最终在内部调用了不同版本的f函数,这就是动态绑定。

如果F的形参改成普通类型,那么两次都会调用基类的f函数,其中F(y)会把y隐式类型转换为一个A类型的临时变量传给形参。

6.如果一个派生类虚函数需要调用其基类版本,但没有使用“基类::”修饰,则运行时该调用会被解析为对其自身的调用,这将导致无限递归。

7.派生类中的虚函数可以在形参后加override,显式告知编译器该虚函数覆盖了其基类版本。

C++基类、派生类、虚函数的几个知识点的更多相关文章

  1. C++:抽象基类和纯虚函数的理解

    转载地址:http://blog.csdn.net/acs713/article/details/7352440 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ...

  2. C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构

    一.基类指针.派生类指针 父类指针可以new一个子类对象 二.虚函数 有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数? 有解决方案,这个对象指针必须是一个父类类型 ...

  3. (转)(C++)关于抽象基类和纯虚函数

    ★抽象类:一个类可以抽象出不同的对象来表达一个抽象的概念和通用的接口,这个类不能实例化(创造)对象. ★纯虚函数(pure virtual):在本类里不能有实现(描述功能),实现需要在子类中实现.例: ...

  4. C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类

    类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. //单继承的定义 class B:public A { ...

  5. C++入门经典-例8.9-抽象类,纯虚函数,创建纯虚函数

    1:包含有纯虚函数的类称为抽象类,一个抽象类至少具有一个纯虚函数.抽象类只能作为基类派生出的新的子类,而不能在程序中被实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针.在程序开发过程中并 ...

  6. 继承虚函数浅谈 c++ 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。

    本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了 应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候 ...

  7. 自绘CListCtrl类,重载虚函数DrawItem

    //自绘CListCtrl类,重载虚函数DrawItem void CNewListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TOD ...

  8. C++中继承 声明基类析构函数为虚函数作用,单继承和多继承关系的内存分布

    1,基类析构函数不为虚函数 #include "pch.h" #include <iostream> class CBase { public: CBase() { m ...

  9. c++ 类内部函数调用虚函数

    做项目的过程中,碰到一个问题. 问题可以抽象为下面的问题: 普通人吃饭拿筷子,小孩吃饭拿勺子. class People { public: void eat() { get_util_to_eat( ...

随机推荐

  1. 【转】Android之四大组件、六大布局、五大存储

    文章来自:http://blog.csdn.net/shenggaofei/article/details/52450668 一.四大组件: Android四大组件分别为activity.servic ...

  2. Starting MySQL... ERROR! The server quit without updating PID file (/home/mysql-5.6.43/data/localhost.localdomain.pid).

    启动MySQL出现如下错误 May :: localhost mysqld: Starting MySQL... ERROR! The server quit without updating PID ...

  3. 阿里云ECS服务器,mysql无法外网访问

    可参考https://www.jianshu.com/p/7a41734b502e 问题原因 未授权远程IP地址登录.root用户默认只能在localhost也就是本机登录 解决方案 在服务器上登录数 ...

  4. codewars--js--Simple string expansion+ repeat(),includes()方法

    问题描述: Consider the following expansion: solve("3(ab)") = "ababab" -- "ab&qu ...

  5. 常用MySQL操作

    常用MySQL操作 更改MySQL数据库root的密码 将绝对路径加入环境变量并设置开机启动 # PATH=$PATH:/usr/local/mysql/bin # echo "PATH=$ ...

  6. TChart-图表的滚动与翻译

    界面代码: object Form1: TForm1 Left = Top = Width = Height = Caption = 'Form1' Color = clBtnFace Font.Ch ...

  7. 显示层封装及实现与优化(无动画+css3动画+js动画)

    showhide.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  8. Spring Boot从入门到精通(一)搭建第一个Spring Boot程序

    Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过 ...

  9. Mac下appium-doctor提示错误汇总

    一.            提示 [Error: Could not detect Mac OS X Version from sw_vers output: '10.12'] 解决方法: 1.终端执 ...

  10. Windows下 JDK1.8环境配置

    安装JDK1.8,安装时会安装jdk.jre. 如果只是在IDEA中写写代码,安装完jdk,在IDEA中指定jdk路径就可以了. 如果要在命令行下执行jdk的命令,比如java.javac,或者要使用 ...