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

名字遮蔽:基类的成员函数和派生类的成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数。

名字遮蔽:如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,通过派生类对象或者在派生类的成员函数中使用该成员时,将使用派生类新增的成员,而不是基类的。

当存在继承关系时,基类的作用域嵌套在派生类的作用域中。如果成员在派生类的作用域中已经找到,就不会在基类作用域中继续查找;如果没有找到,则继续在基类作用域中查找。

在这里插入图片描述

基类的成员函数和派生类的成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数。

基类
在这里插入图片描述
派生类
在这里插入图片描述
在这里插入图片描述
派生类将基类覆盖掉了,就是派生类和基类不能重载。
在这里插入图片描述

将派生类的注释掉,基类函数实现重载
在这里插入图片描述
在这里插入图片描述

类作用域

  1. 在成员名前面加类名和域解析符可以访问对象的成员。
  2. 如果不存在继承关系,类名和域解析符可以省略不写。
  3. 当存在继承关系时,基类的作用域嵌套在派生类的作用域中。如果成员在派生类的作用域中已经找到,就不会在基类作用域中继续查找;如果没有找到,则继续在基类作用域中查找。
  4. 如果在成员的前面加上类名和域解析符,就可以直接使用该作用域的成员。

在类的作用域之外,普通的成员只能通过对象(可以是对象本身,也可以是对象指针或对象引用)来访问,静态成员可以通过对象访问,也可以通过类访问。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。
               
class A {        // 基类
public:
    int m_a=10;
    void func() { cout << "调用了A的func()函数。\n"; }
};
               
class B :public A {       // 子类
public:
    int m_a = 20;
    void func() { cout << "调用了B的func()函数。\n"; }
};
           
class C :public B {       // 孙类
public:
    int m_a = 30;
    void func() { cout << "调用了C的func()函数。\n"; }
    void show() {
        cout << "C::m_a的值是:" << C::m_a << endl;
        cout << "B::m_a的值是:" << B::m_a << endl;
        cout << "A::m_a的值是:" << B::A::m_a << endl;
    }
};
           
int main()
{           
    C c;
    cout << "C::m_a的值是:" << c.C::m_a << endl;
    cout << "B::m_a的值是:" << c.B::m_a << endl;
    cout << "A::m_a的值是:" << c.B::A::m_a << endl;
    c.C::func();
    c.B::func();
    c.B::A::func();
}

在一个例子:
基类:
在这里插入图片描述
在这里插入图片描述

派生类:
在这里插入图片描述
在这里插入图片描述

继承的特殊关系

派生类和基类之间有一些特殊关系。

  1. 可以把派生类对象赋值给基类对象(包括私有成员),但是,会舍弃非基类的成员。
#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

class A {        // 基类
public:
    int m_a=0;
private:
    int m_b=0;
public:
    // 显示基类A全部的成员。
    void show() { cout << "A::show() m_a=" << m_a << ",m_b=" << m_b << endl; }
    // 设置成员m_b的值。
    void setb(int b) { m_b = b;  }
};

class B :public A        // 派生类
{
public:
    int m_c=0;
    // 显示派生类B全部的成员。
    void show() { cout << "B::show() m_a=" << m_a << "m_c=" << m_c << endl; }
};

int main()
{

    A a;
    B b;

    b.m_a = 10;
    b.setb(20);
    b.m_c = 30;

    a.show();
    a = b;
    b.show();

    // B b;
    // A* a = &b;

    // b.m_a = 10; 
    // b.setb(20);          // 设置成员m_b的值。
    // b.m_c = 30;
    // b.show();            // 调用的是B类的show()函数。

    // a->m_a = 11;
    // a->setb(22);          // 设置成员m_b的值。
    // // a->m_c = 30;
    
    // a->show();         // 调用的是A类的show()函数。
}
  1. 基类指针可以在不进行显式转换的情况下指向派生类对象。
  2. 基类引用可以在不进行显式转换的情况下引用派生类对象。
  3. 如果函数的形参是基类,实参可以用派生类。

基类指针或引用只能调用基类的方法,不能调用派生类的方法。

#include <iostream>         // 包含头文件。
using namespace std;        // 指定缺省的命名空间。

class A {        // 基类
public:
    int m_a=0;
private:
    int m_b=0;
public:
    // 显示基类A全部的成员。
    void show() { cout << "A::show() m_a=" << m_a << ",m_b=" << m_b << endl; }
    // 设置成员m_b的值。
    void setb(int b) { m_b = b;  }
};

class B :public A        // 派生类
{
public:
    int m_c=0;
    // 显示派生类B全部的成员。
    void show() { cout << "B::show() m_a=" << m_a << "m_c=" << m_c << endl; }
};

int main()
{

    B b;
    A* a = &b;

    b.m_a = 10;
    b.setb(20);
    b.m_c = 30;
    b.show();

    a->m_a=10;
    a->setb(20);
    a->show();

    // B b;
    // A* a = &b;

    // b.m_a = 10; 
    // b.setb(20);          // 设置成员m_b的值。
    // b.m_c = 30;
    // b.show();            // 调用的是B类的show()函数。

    // a->m_a = 11;
    // a->setb(22);          // 设置成员m_b的值。
    // // a->m_c = 30;
    
    // a->show();         // 调用的是A类的show()函数。
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值