You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中派生类未定义拷贝构造器为何能复制基类私有成员?

关于C++拷贝构造函数自动生成与基类私有成员复制的疑惑

在类B的自定义拷贝构造器(参数为string lan、const B& kop)的初始化列表中,我调用了未定义的B(kop),编译器自动生成该拷贝构造器后,居然能复制基类A的私有成员lan、licz以及B自身的成员tf。我原本认为基类私有成员必须通过公共setter才能访问,而且licz根本没有setter,但程序却正常运行,想从技术角度搞清楚编译器的处理逻辑。


相关代码

abc.h

#ifndef ABC_H_INCLUDED
#define ABC_H_INCLUDED
#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

class A
{
private:
    string lan;
    int licz;

public:
    A(string lan, int licz) : lan(lan), licz(licz) {}

    virtual void drukuj() const
    {
        cout<<lan<<" ; "<<licz<<endl;
    }

    string getLen() const
    {
        return lan;
    }

    int getLicz() const
    {
        return licz;
    }

    void setString(string lan)
    {
        this->lan=lan;
    }
};

class B : public A
{
private:
    bool tf;

public:
    B(string lan, int licz, bool tf) : A(lan,licz), tf(tf){}
    B(string lan, const B& kop) : B(kop)
    {
        A::setString(lan);
    }

    void drukuj() const override
    {
        cout<<boolalpha<<A::getLen()<<" ; "<<A::getLicz()<<" ; "<<tf<<endl;
    }
};


#endif // ABC_H_INCLUDED

main.cpp

#include "abc.h"

int main()
{
    A a("obiekt klasy A",1);
    B b("obiekt klasy B", 2, true);
    B c("kopia obiektu b", b);
    a.drukuj();//drukuje wszystkie składowe obiektu a
    b.drukuj(); c.drukuj();

    return 0;
}

技术解释

1. 编译器自动生成拷贝构造函数的核心逻辑

你在B的构造器初始化列表中写B(kop)是委托构造语法,委托给B的拷贝构造函数。由于你没有显式定义B的拷贝构造函数,编译器会自动生成一个默认拷贝构造函数,它会完成两个关键操作:

  • 调用基类A的默认拷贝构造函数(A也无显式定义,编译器同样会自动生成);
  • 逐成员拷贝B自身的非静态成员(即tf)。

2. 基类私有成员的复制规则

你误以为基类私有成员只能通过setter访问,这是类外部代码的访问限制。但编译器生成的拷贝构造函数属于类的特殊成员函数,天生拥有对类所有成员(包括私有成员)的访问权限。

对于A的自动生成拷贝构造函数来说,它会直接读取源对象的私有成员lan和licz,将值逐位(或逐成员,如string这类非POD类型)复制到新对象的对应成员中,完全不需要通过getter/setter。而B的自动生成拷贝构造函数会自动调用A的拷贝构造函数,完成基类部分的复制,这是编译器的内置行为,无需手动干预。

3. 自定义构造器的执行流程

你的B(string lan, const B& kop)构造器执行顺序是:

  1. 先委托调用B的自动生成拷贝构造函数,完成基类A的lan、licz和B自身tf的复制;
  2. 然后在构造函数体中调用A::setString(lan),将基类的lan成员替换为你传入的新字符串。

这就是最终c对象的lan是"kopia obiektu b",而licz、tf与b一致的原因——licz通过A的拷贝构造函数复制后未被修改,tf则由B的拷贝构造函数直接复制。

4. 为何不需要显式setter

编译器生成的特殊成员函数(拷贝构造、拷贝赋值等)是C++语言底层提供的对象复制机制,它们属于类的内部实现逻辑,不受成员访问权限的约束。getter/setter是给类外部代码提供的访问接口,底层的对象复制操作完全不需要经过这一层。


内容的提问来源于stack exchange,提问作者urshuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:12:48