云计算百科
云计算领域专业知识百科平台

Person p2 = Person(p); 的 = 没有调用用户自定义的或者编译器默认生成的 operator=

class Person{
public:
Person(){
cout << "no param contructor!" << endl;
mAge = 10;
}
Person(int age){
cout << "param constructor!" << endl;
mAge = age;
}
Person(const Person& person){
cout << "copy constructor!" << endl;
mAge = person.mAge;
}
~Person(){
cout << "destructor!" << endl;
}
public:
int mAge;
};

Person p2 = Person§;里的这个=**没有调用operator=`**——不管是用户自定义的还是编译器默认生成的,都没被用到。

关键区别:拷贝初始化 vs 赋值

C++ 里 = 在两种不同场合含义完全不同:

场合一:定义对象的同时用 = 初始化(你这行代码就是这种)

Person p2 = Person(p); // 这是"拷贝初始化"(copy-initialization)

这其实是声明语句的一部分,等价写法是 Person p2(Person(p));。编译器看到这种写法,做的事情是选择一个构造函数来构造 p2,跟 operator= 毫无关系。

场合二:对象已经存在,之后再用 =

Person p2; // 先用默认构造函数把 p2 构造出来
p2 = p; // 这时候才是真正的"赋值",调用 operator=

只有这种——对象已经存在,你再对它做 = xxx——才是调用赋值运算符。

Person p2 = Person(p); 过程

  • Person(p):显式调用拷贝构造函数,用 p 构造出一个临时对象 → 打印一次 "copy constructor!"
  • 这个临时对象用来初始化 p2:因为是同类型对象的拷贝初始化,从 C++17 开始这一步是强制拷贝省略(guaranteed copy elision,C++17 之前多数编译器也会做 RVO 优化,只是标准不强制),临时对象直接"原地"构造成 p2,不会再额外调用一次拷贝/移动构造函数。
  • 所以实际运行你会看到 p2 那一行只打印一次 "copy constructor!",而不是两次。

    编译器生成的默认 operator=

    Person 类确实会被编译器隐式生成一个默认赋值运算符(因为你没有自己写,且成员只是内置类型 int,满足生成条件)。它长这样(编译器帮你隐式生成的,逐成员拷贝):

    Person& operator=(const Person& person){
    mAge = person.mAge;
    return *this;
    }

    但这个函数在你贴的代码里从头到尾没被调用过,因为 p1、p2、p3 全部是"定义时初始化",走的都是构造函数(拷贝构造)。你想真正看到它被调用,得这样写:

    Person p4; // 先构造
    p4 = p; // 这里才会打印一次 operator= 里的内容(如果你在里面加了 cout)

    一句话总结:判断 = 是初始化还是赋值,看左边的对象此刻是不是"刚刚被声明、第一次拥有值"——是的话就是初始化(调用构造函数),不是的话(对象早就存在了)才是赋值(调用 operator=)。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Person p2 = Person(p); 的 = 没有调用用户自定义的或者编译器默认生成的 operator=
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!