【C++】继承时的名字遮蔽&&派生类的构造函数

c++学习总结 本文深入探讨了C++继承体系中的关键概念,包括: 名字遮蔽机制:当派生类定义与基类同名的成员时,基类成员会被遮蔽,可通过显式域解析符访问; 类作用域规则:每个类构成独立作用域,继承形成嵌套作用域,成员查找遵循派生类优先原则; 多态实现:通过虚函数和基类指针/引用实现动态绑定,详细解析了虚函数表(vtable)和虚表指针(vptr)的工作原理; 继承关系特性:包括公有继承权限、对象切片、基类指针/引用指向派生类对象等特殊行为; 多继承问题:重点分析了菱形继承的数据冗余和二义性问题,以及虚继承的解决方案; 多 阅读详情

如果派生类和基类中的成员相同,会发生什么情况呢?

  如果派生类和基类的成员变量或者成员函数相同,那么就会遮蔽从基类继承来的成员函数或者成员变量,即使用新增的成员变量,而不是使用继承来的。

/*************************************************************************
    > File Name: 继承_名字遮蔽.cpp
    > Author: Tanswer_
    > Mail: 98duxm@gmail.com
    > Created Time: 2016年10月05日 星期三 17时50分36秒
 ************************************************************************/

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <set>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;

//基类
class People
{
protected:
    string  name;
    int     age;
public:
    void    setName(string );
    void    setAge(int );
    string  getName();
    int     getAge();
    void display();
};

/*基类中的display()函数*/
void People::display()
{
    cout << "People--name: " << name << "    age:" << age << endl;
}

void People::setName(string name)
{
    this->name = name;
}


void People::setAge(int age)
{
    this->age = age;
}

string People::getName()
{
    return name;
}

int People::getAge()
{
    return this->age;
}

//派生类--Student
class Student: public People
{
private:
    float   score;
public:
    using People::name;
    using People::age;
    void    setScore(float );
    float   getScore();
    void    display();
};

/*派生类中的display()函数*/
void Student::display()
{
    cout << "Stu name: " << name << "  age: " << age << endl;    
}

void Student::setScore(float score)
{
    this->score = score;
}

float Student::getScore()
{
    return score;
}

int main()
{
    Student stu;
    stu.setName("小明");
    stu.setAge(19);
    stu.setScore(99.9f);

   // cout << stu.getName() << "   年龄是: " << stu.getAge() << "   成绩是:" << stu.getScore() << endl;
    stu.display();
    stu.People::display();

    return 0;
}

输出结果为:

Stu name: 小明  age: 19
People--name: 小明    age:19

  本例中基类和派生类都定义了display()成员函数,会造成遮蔽,stu 是Student的对象,所以默认使用派生类Student中的display()。不过基类People中的display()函数仍然可以访问,只是要加上类名和域解析符。

派生类的构造函数

基类的构造函数不能被继承,所以声明派生类的时候,对基类的成员的初始化也要由派生类的构造函数来完成。

解决这个问题的思路是:执行派生类的构造函数时,要把基类的构造函数加上。

/*************************************************************************
    > File Name: 继承_派生构造.cpp
    > Author: Tanswer_
    > Mail: 98duxm@gmail.com
    > Created Time: 2016年10月07日 星期五 22时32分18秒
 ************************************************************************/

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <set>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
class People
{
protected:
    string name;
    int age;
public:
    People(string ,int );  //基类构造函数声明
};

//基类构造函数
People::People(string name,int age): name(name),age(age) {}

//派生类
class Student: public People
{
private:
    float score;
public:
    Student(string ,int ,float );
    void display();
};

/*派生类的构造函数写法1
Student::Student(string name,int age,float score): People(name,age) {
    this -> score = score;
}
*/

//写法2
Student::Student(string name,int age,float score) :People(name,age),score(score) {}

void Student::display()
{
    cout << "name: " << name << endl;
    cout << "age : " << age << endl;
    cout << "score: " << score << endl;
}

int main()
{
    Student stu("小明",19,99.0);
    stu.display();

    return 0;
}

输出结果:

name: 小明
age : 19
score: 99

  我们可以看到上面两种写法,要注意的是 派生类冒号后面是对基类构造函数的调用而不是声明,括号里的参数是实参,不仅可以写变量,还可以写常量、局部变量等。

基类构造函数调用规则

  事实上,通过派生类创建对象时必须要调用基类的构造函数,这是语法规定。定义派生类构造函数时最好指明基类构造函数,如果基类有默认构造函数(不带参数的构造函数),那么可以不指明,系统会默认调用,如果没有,那么必须要指明,否则系统不知道如何调用基类的构造函数,编译失败。

/*************************************************************************
    > File Name: 继承_派生构造.cpp
    > Author: Tanswer_
    > Mail: 98duxm@gmail.com
    > Created Time: 2016年10月05日 星期三 22时32分18秒
 ************************************************************************/

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <set>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
class People
{
protected:
    string name;
    int age;
public:
    People();
    People(string ,int );
};

/*基类构造函数带参数的构造函数*/
People::People(string name,int age): name(name),age(age) {}

/*不带参数*/
People::People() {
    this -> name = "xxx";
    this -> age = 0;
}

//派生类
class Student: public People
{
private:
    float score;
public:
    Student();
    Student(string ,int ,float );
    void display();
};

/*带参数的构造函数*/
Student::Student(string name,int age,float score) :People(name,age),score(score) {}

/*不带参数*/
Student::Student(){
    this -> score = 0.0;
}

void Student::display()
{
    cout << "name: " << name << endl;
    cout << "age : " << age << endl;
    cout << "score: " << score << endl;
}

int main()
{
    Student stu1;
    stu1.display();

    Student stu2("小明",19,99.0);
    stu2.display();

    return 0;
}

输出结果为:

name: xxx
age : 0
score: 0
name: 小明
age : 19
score: 99

  创建stu1时,执行Student::Student(),它并没有指明调用基类的哪个构造函数,系统默认调用不带参数的,如果将People::People()这个构造函数删除,则会发生编译错误,因为创建对象stu1时,没有调用基类的构造函数。
  创建stu2时,执行带参数的构造函数,它也指明了基类的构造函数。如果将Student::Student(string name ,int age,float score)函数中的People(name,age)去掉,就会调用基类的默认构造函数,输出结果变为 

name: xxx
age : 0
score: 99

 构造函数的调用顺序

为了直观地看清这个问题,我们把上面的程序修改一下。

/*基类构造函数*/
People::People(string name,int age): name(name),age(age) {
    cout << "People::People(string, int )" << endl;
}

People::People() {
    this -> name = "xxx";
    this -> age = 0;
    cout << "People::People" << endl;
}
/*派生类*/
Student::Student(string name,int age,float score) :People(name,age),score(score) {
    cout << "Student::Student(string ,int ,float )" << endl;
}

Student::Student(){
    this -> score = 0.0;
    cout << "Student::Student()" << endl;
}

主函数 我们这样写:

{
    Student stu1;
    //stu1.display();

    cout << "-----------------" << endl;
    Student stu2("小明",19,99.0);
    //stu2.display();

    return 0;
}

输出结果为:

People::People
Student::Student()
-----------------
People::People(string, int )
Student::Student(string ,int ,float )

从上面可以看出,构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。


c++继承构造函数 【1】为什么需要继承构造函数? 首先,看看如下代码片段: 1 struct A 2 { 3 A(int i) 4 {} 5 }; 6 7 struct B : A 8 { 9 B(int i) : A(i) 10 {} 11 }; 在C++中非常常见:B派生于A,B在构造函数中调用A的构造函数,从而完成构造函数的“传递”。 有时候,基类可能拥有数量众多的不同版本的构造函数(这样的情况并不少见)。 那么,倘若基类中有大量的构造函数 阅读详情

相关推荐

[C++ 从入门到精通] 13.派生类、调用顺序、继承方式、函数遮蔽

派生类:在C++中,继承就是在一个已存在的类的基础上建立一个新的类。已存在的类称为「基类」,又称为「父类」;新建立的类称为「派生类」,又称为「子类」

Loewen丶的小窝 1338

C++继承时的名字遮蔽问题

C++继承时的名字遮蔽问题

Elanie1024的博客 501

高程 | 继承与派生(c++)

类的继承,是新的类从已有类那里得到已有的特性。类的派生,从已有类产生新类的过程。

知识库搭建ing 2943

c++基本使用--名字遮蔽与类作用域/继承的特殊关系

名字遮蔽与类作用域/继承的特殊关系

记录我目之所及的世界 267

GD32F4x芯片加密实战:从读保护到安全启动全解析

本文详细解析了GD32F4x芯片加密的实战操作,从读保护功能到安全启动全流程。通过具体代码示例和应用场景分析,帮助开发者有效防止固件被盗用,提升工业控制、智能门锁等场景下的数据安全性。重点介绍了读保护功能的底层机制、配置步骤及常见问题解决方案。

weixin_42629671的博客 207

GNSS接收机性能测试全攻略:从实验室到真实场景

本文系统介绍了GNSS接收机从实验室到真实场景的完整性能测试流程。首先通过GNSS模拟器进行射频传导测试,评估接收机的基础性能;其次进行天线OTA测试,考察整机系统表现;最后通过精心设计的外场路测,在复杂环境中验证其实际定位精度与可靠性。文章强调,只有结合可控的实验室验证与多变的外场挑战,才能对接收机性能做出全面、真实的评价。

weixin_28365523的博客 515

20180321 C++ 避免遮掩继承而来的名称

20180321 C++ 避免遮掩继承而来的名称C++的名称遮掩规则(name-hiding relue)所做的唯一事情就是:遮掩名称。至于名称是否是相同或不同的类型,并不重要,如double类型的局部变量x遮掩了int类型的全局变量x。现在考虑继承关系:eg:class Base{private:  int x;public :  virtual void mf1() = 0;  virtual...

weixin_39089680的博客 295

解决vscode 连接服务器报错:The remote host may not meet VS Code Server‘s prerequisites for glibc and libstdc++

解决vscode远程连接服务器报错:The remote host may not meet VS Code Server's prerequisites for glibc and libstdc++ (The remote host does not meet the prerequisites for running VS Code Server)

qq_37200100的博客 9910

C++ 继承详解

C++ 继承继承语法继承方式改变访问权限名字遮蔽继承时的对象模型无变量遮蔽有变量遮蔽 继承语法 继承的一般语法为: class 派生类名:[继承方式] 基类名{ 派生类新增加的成员 }; 继承方式 继承方式包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private。不同的继承方式会影响基类成员在派生类中的访问权限。 (1)public继承方式 基类中所有 public 成员在派生类中为 public 属性; 基类中

TABE_的博客 1万+

计数译码驱动显示电路实验报告_京东方G0A电路、阵列基板、显示 装置及驱动方法广州威彩...

图1、实施例二所述的选择子单元的结构示意图图2、实施例四所述的GOA电路结构示意图图3、实施例七所述的阵列基板的局部结构示意图图4、实施例所述的极性反转驱动方法的第一场的各信号时序图图5、实施例所述的极性反转驱动方法的第二场的各信号时序图图6、实施例所述的极性反转驱动方法的第三场的各信号时序图图7、实施例所述的极性反转驱动方法的第四场的各信号时序图图8、为图4所示时序下,实施例八所述显示...

weixin_35696112的博客 924

Xilinx Aurora 8B/10B IP核详解和仿真

Xilinx Aurora 8b/10b IP核的详解,以及使用与仿真示例,对IP核的配置和如何仿真有非常详细的说明,除了对IP核官方文档的内容进行了解析以外,还对GTX引脚的选择等比较容易混淆和不好理解的地方进行了说明。最后对IP核的仿真运行进行了STEP BY STEP 的说明,对仿真的结果也进行了简要的说明。 该文档对Xilinx FPGA和ZYNQ SOC下 AURORA 8B/10B IP核的使用提供了一个快速上手的指导。

weixin_43354598的博客 1万+

C++基础——继承时的名字遮蔽问题

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。 下面是一个成员函数的名字遮蔽的例子: #include<iostream> using namespace std; //基类People class People{ public: void show(); protec...

一个小孩 365

lammps教程:官方自带eam_database程序拟合EAM势方法介绍

使用lammps模拟金属体系,最常用的势函数为eam、meam势。 对于大多数金属或者合金来说,可以从网上下载相对应的eam或meam势力场文件。 而对于一些新的合金材料,可能就找不到相对应的力场文件。 解决的方法有两种,一是采用混合势(pair_style hybrid),第二种方法是自己拟合势函数文件。 混合势的写法在前面文章中已经介绍过,本文介绍一种拟合EAM势的方法。 该方法是运行Xiaowang Zhou编写的一个拟合程序,该程序可自动生成所需要的合金势。 这个程序能够拟合的合金元素有: Cu,

lammps_jiayou的博客 4613

C++继承时名字的遮蔽

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。 成员函数的名字遮蔽: #include<iostream> using namespace std; //基类People class ...

weixin_45743799的博客 332

9、眼底图像智能分析:糖尿病视网膜病变的自动化识别与分级系统

本博客介绍了一种基于深度学习的糖尿病视网膜病变(DR)自动化识别与分级系统。该系统通过视网膜图像的预处理、数据增强、集成模型的构建与优化,实现了对DR的高效识别与分级。识别系统采用二分类任务,准确率达到97.67%,而分级系统通过四分类策略取得了95.2%的准确率。系统在基层社区和医院中具有广泛的应用前景,为DR的早期筛查和精准诊断提供了有效工具。

pea55的博客 144

CAPL学习之路-关键字

在capl中,关键字具有特殊的含义和用途,因此,不得将关键字用作变量或函数的名称 声明数据类型的关键字 可以用不同的关键字,声明或引用不同类型的数据 byte 声明一个字节的变量 word 声明两个字节的变量 dword 声明四个字节的变量 int 声明两个字节的整数 long 声明四个字节的变量 qword 声明八个字节的变量 char 声明一个字符串 float 声明一个浮点数,8个字节 double 声明一个浮点数,8个字节 定义一个结构体或枚举类型 struct struct Data { .

jasonj333 6107

c++继承和派生(个人总结笔记)

一、继承和派生 1、C++继承的概念及语法 继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承类似,例如儿子继承父亲的财产。 继承(Inheritance) 可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数。被继承的类称为父类或基类,继承的类称为子类或派生类。 继承方式包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 priva

junxuezheng的博客 2292

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++继承详解

小编这些年深知大多数初中级Java工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。原文链接:https://gitee.com/hh090807。

song99911的博客 1100

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

C++基础 名字遮蔽

问答: 什么叫名字遮蔽? 派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员,这就叫做名字遮蔽。 有一点要提出,对于继承而言,只要名字一样不管形参个数和类型怎样,都构成名字遮蔽。 会产生怎样的后果? 派生类并没有继承到基类的重名的成员函数,它用的是自己的成员函数。换句话说,派生类自己的重名函数把基类的给覆盖了,导致派生类自己使用自己的不能使用基类的。

识海拾贝的博客 598

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++——名字遮蔽与类的作用域

C++——类的作用域以及继承的特殊关系

MaoSiri的博客 694

C++继承时的名字遮蔽

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。 范例 #include<iostream> using namespace std; //基类People class People{ public: void show(); protected: char *m_nam

zzwwgg1984的博客 180

C++学习16 继承时的名字遮蔽

如果派生类中的成员变量和基类中的成员变量重名,那么就会遮蔽从基类继承过来的成员变量。所谓遮蔽,就是使用新增的成员变量,而不使用继承来的。 成员函数也一样,如果函数名和参数签名都相同,就会造成遮蔽。如果仅仅是函数名相同,而参数签名不同,那么会构成重载。 请看下面的例子: #include<iostream> using namespace std; class P...

dengaoxin0873的博客 147

C++继承和派生

被继承的类称为父类或基类,继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼,“基类”和“派生类”通常放在一起称呼。派生类除了拥有基类的成员,还可以定义自己的新成员,以增强类的功能。以下是两种典型的使用继承的场景:1) 当你创建的新类与现有的类相似,只是多出若干成员变量或成员函数时,可以使用继承,这样不但会减少代码量,而且新类会拥有基类的所有功能。2) 当你需要创建多个类,它们拥有很多相似的成员变量或成员函数时,也可以使用继承。

tecoes的博客 1108
上一篇: 【C++】继承语法&&继承方式
下一篇: 【C++】智能指针的设计与实现
Tanswer_
博客等级 码龄11年 231粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值