C++继承中父类和子类之间的同名覆盖

本文深入探讨了C++中父类和子类的同名成员变量及函数的处理方式,包括成员变量的隐藏与访问,以及同名成员函数的重写而非重载,通过实例代码展示了如何使用作用域分辨符解决冲突。

1 C++继承中父类和子类的同名成员变量

1.1 父类和子类的同名成员变量

思考:子类中是否可以定义父类中的同名成员?如果可以,如何区分?

父子间的冲突:

  • 子类可以定义父类中的同名成员。
  • 子类中的成员将隐藏父类中的同名成员。
  • 父类中的同名成员依然存在于子类中。
  • 通过作用域分辨符(::)访问父类中的同名成员。

访问父类中的同名成员:
在这里插入图片描述
同名变量深度分析:

#include <iostream>
#include <string>

using namespace std;

namespace A
{
    int g_i = 0;
}

namespace B
{
    int g_i = 1;
}

class Parent
{
public:
    int mi;
    
    Parent()
    {
        cout << "Parent() : " << "&mi = " << &mi << endl;
    }
};

class Child : public Parent
{
public:
    int mi;
    
    Child()
    {
        cout << "Child() : " << "&mi = " << &mi << endl;
    }
};

int main()
{
    Child c;
    
    c.mi = 100;    
    
    c.Parent::mi = 1000;
    
    cout << "&c.mi = " << &c.mi << endl;
    cout << "c.mi = " << c.mi << endl;
    
    cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
    cout << "c.Parent::mi = " << c.Parent::mi << endl;
    
    return 0;
}

2 C++继承中父类和子类的同名成员函数

2.1 父类和子类中的同名成员函数

思考一个问题:子类中定义的函数是否能够重载父类中的同名函数?

类中的成员函数可以进行重载,我们需要再来回顾下重载的概念:

  • 重载函数的本质为多个不同的函数。
  • 函数名和参数列表是唯一的标识。
  • 函数重载必须发生在同一个作用域中。

我们必须知道父类和子类属于不同的作用域,所以子类中的函数不能够 重载父类中同名函数。

所以,对于子类和父类中的同名函数:

  • 子类中的函数将隐藏父类的同名函数(跟参数列表无关)。
  • 子类无法重载父类中的成员函数。
  • 使用作用域分辨符访问父类中的同名函数。
  • 子类可以定义父类中完全相同的成员函数。

父子间的同名函数:

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
};

class Child : public Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
    
    void add(int x, int y, int z)
    {
        mi += (x + y + z);
    }
};

int main()
{
    Child c;
    
    c.mi = 100;    
    
    c.Parent::mi = 1000;
    
    cout << "c.mi = " << c.mi << endl;
    
    cout << "c.Parent::mi = " << c.Parent::mi << endl;
    
    c.add(1);
    c.add(2, 3);
    c.add(4, 5, 6);
    
    cout << "c.mi = " << c.mi << endl;
    
    cout << "c.Parent::mi = " << c.Parent::mi << endl;
    
    return 0;
}

参考资料:

  1. C++深度解析教程
<think>好的,我现在要回答用户关于C++子类大小与父类成员关系的问题。首先,我需要回顾用户提供的引用资料,看看有没有相关的信息。引用1提到子类继承父类的成员函数,如果没重写的话,会共享同一段内存。引用34讨论了子类父类的成员变量如何访问修改。特别是引用3中的代码示例,展示了子类如何继承父类的成员变量x,同时自己又定义了同名的x,导致子类对象中有两个不同的x变量。这可能子类的大小有关。 首先,子类的大小通常包括父类的所有非静态成员变量,再加上子类自己定义的成员变量。但如果有同名变量,子类会隐藏父类的变量,但父类的变量仍然存在于内存中,只是需要通过作用域运算符来访问。比如引用3中的例子,子类C继承自Base,Base有x=10,但子类C自己定义了x=0,所以在C的实例中,会有两个int变量x,一个是Base的,一个是C自己的。因此,子类的大小应该是父类Base的大小加上子类C新增成员的大小。Base有一个int x,C也有一个int x,所以C的大小应该是两个int的大小,即8字节(假设int是4字节)。 不过还需要考虑内存对齐的问题。如果父类子类有其他成员变量,或者有虚函数,那么可能会有虚表指针,这也会影响大小。但根据用户提供的引用,目前讨论的情况不涉及虚函数,只是普通成员变量。 另外,引用1提到成员函数在代码段共享,不会影响对象的大小,因为函数代码不占用对象的内存空间。所以子类的大小主要由成员变量决定,包括继承自己定义的。 接下来,需要考虑继承方式的影响。如果是虚继承,可能会有虚基类指针,但用户的问题中没有提到虚继承,所以暂时不考虑这种情况。用户的问题主要关注父类成员变量如何影响子类的大小。 总结一下,子类的大小等于父类所有非静态成员变量的大小,加上子类自身非静态成员变量的大小,同时考虑内存对齐。如果有同名变量,父类的变量仍然存在,不会被覆盖,只是被隐藏,因此也会占据内存空间。 用户可能还会想知道如果父类有多个成员变量,或者子类有多个父类(多继承)的情况,这时候子类的大小如何计算。根据引用2提到的多继承,每个父类的成员变量都会被包含在子类中,所以多继承子类的大小是各个父类成员变量之加上子类自己的成员变量,同样考虑对齐。 最后,需要给出一个清晰的回答,分点说明,并结合例子,可能的话用代码示例来展示不同情况下的子类大小。</think>在C++中,子类的大小与父类成员的关系可以通过以下要点理解: ### 1. 内存构成规则 - **子类内存 = 父类非静态成员 + 子类非静态成员** - **成员函数不占用对象内存**,父类子类共享代码段的成员函数[^1] - 示例: ```cpp class Base { int x; }; // sizeof(Base) = 4 class Derived : Base { int y; };// sizeof(Derived) = 8 ``` ### 2. 同名成员变量的处理 - **同名变量独立存在**,父类成员通过作用域运算符访问[^3] - 示例: ```cpp class Base { public: int x=2; }; class Child : public Base { public: int x=0; // 与Base::x共存 void show() { cout << Base::x; // 访问父类x cout << x; // 访问子类x } }; // sizeof(Child) = 8(两个int) ``` ### 3. 构造/析构的影响 - 实例化子类时,**父类构造函数优先执行**,完成父类成员的初始化[^2] - 析构时子类析构函数先执行,再执行父类析构函数 ### 4. 多继承场景 - **子类包含所有父类的成员**,可能出现内存空洞(对齐) - 示例: ```cpp class A { char a; }; // sizeof=1+3(padding)=4 class B { int b; }; // sizeof=4 class C : A, B { char c; };// sizeof=4(A)+4(B)+1+3=12 ``` ### 5. 验证示例 ```cpp #include <iostream> using namespace std; class Father { public: int f1 = 10; char f2; }; // sizeof=8(4+1+3对齐) class Son : public Father { public: int s1; virtual void func() {} // 虚表指针8字节(64位系统) }; int main() { cout << "Father:" << sizeof(Father) << endl; // 输出8 cout << "Son:" << sizeof(Son) << endl; // 输出20(父类8 + int4 + vptr8) return 0; } ``` ### 内存布局示意图 ``` Son对象内存结构: +-----------------+ | Father::f1 (4) | | Father::f2 (1) | | padding (3) | ← 父类部分(8字节) +-----------------+ | vptr (8) | ← 虚函数表指针 +-----------------+ | Son::s1 (4) | | padding (4) | ← 对齐到8字节 +-----------------+ 总大小:8+8+8=24(实际根据编译器优化可能为20) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值