C++构造函数、拷贝构造函数、赋值运算符漫谈(一)——函数参数传递

在讨论C++函数参数之前,我们先来看一下C程序是如何调用函数的。

 

如图,为C语言的函数调用记录,C++也类似。当有如下函数:

void foo(X x0);

如果有如下调用方式:

X xx;

foo(xx);

    编译器(对于C)会将实参xx以“位逐次拷贝”方式复制给形参x0(注:X0即在上图函数活动记录中的参数位置)。在C++中,如果一个Class也展现了“位逐次拷贝语义”【1】,且用户没有定义拷贝构造函数,那么编译器按照这种方式进行拷贝没有问题。但是当一个Class不展现“位逐次拷贝语义”的情况(四种),或者用户定义了拷贝构造函数呢?这种情况编译器必须采用一定措施避免这种直接位拷贝的发生(否则拷贝构造函数将不能发生作用)。C++编译器是这样做的:

     调用函数前,先引入一个X的临时变量temp,并以实参xx为参数调用拷贝构造函数(这由编译器安插代码完成)。如:

X temp;(此处不调用构造函数,只分配空间)

temp.X::X(xx);(这两行代码是由编译器插入)

    之后怎么办呢?如果直接foo(temp),问题又回到之前了,因为只是相当于temp变成了实参,实参到形参x0的拷贝依然是“位逐次拷贝”。所以C++编译器必须做第二个转化,即修改函数foo的声明,将其修改为:

void foo(X& x0);

即函数参数变为引用,传入的将是temp的地址。

测试:

class X
{
public:
X()
{cout<<"X()"<<endl;};
X(const X& x)
{
  cout<<"X(const X& x)"<<endl;
}
X& operator=(const X&)
{
   cout<<"="<<endl;
}
~X()
{cout<<"destructor"<<endl;}
};
void foo(X x0)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
X xx;
foo(xx);
}

运行结果:

 

可以看出函数参数的传入需要调用拷贝构造函数构建一个临时对象(注:并不是构建形参,形参已经被转化为引用,不再是对象),另外临时对象在函数退出时销毁。

总结:函数形参中,对象值传递的方式都转化为临时对象和引用传递。

【1】一个类不展现“位逐次拷贝”的四种情况:

(1) 这个类有member object,并且这个member object对应的Class定义了拷贝构造函数。

(2) 这个类的父类定义了拷贝构造函数。

(3) 这个类中有虚函数(包括其父类有的情况)。

 (4)这个类的继承连中有虚基类。

时间: 2024-11-08 23:30:59

C++构造函数、拷贝构造函数、赋值运算符漫谈(一)——函数参数传递的相关文章

【C/C++学院】(6)构造函数/析构函数/拷贝构造函数/深copy浅copy

1.构造函数     类的初始化即为构造函数.也为:隐式的初始化. 构造函数在对象初始化的时候,自动被调用.隐式的调用. 构造函数分为三种:有参构造函数.无参构造函数.拷贝构造函数. 有参构造函数调用有三种:括号法.等号法.手工法. #include <iostream> using namespace std; class Test { private: int m_a; public: Test()//无参构造函数 { } Test(const Test &obj)//拷贝构造函数

C++中拷贝构造函数的应用详解_C 语言

一.C++中拷贝构造函数的定义: 有一个参数的类型是其类类型的构造函数是为拷贝构造函数. 如下所示: X::X( const X& x); Y::Y( const Y& y, int =0 ); //可以是多参数形式,但其第二个即后继参数都有一个默认值 二.拷贝构造函数的应用: 当一个类对象以另一个同类实体作为初值时,大部分情况下会调用拷贝构造函数. 一般是这三种具体情况: 1.显式地以一个类对象作为另一个类对象的初值,形如X xx=x; 2.当类对象被作为参数交给函数时. 3.当函数返回

C++构造函数、拷贝构造函数、赋值运算符漫谈(二)——函数返回值

 首先我们先看一下C程序的返回值处理情况,我们知道当C函数返回int等小型数据时直接将返回值放入eax寄存器.那当返回大的数据结构又是如何处理呢?看如下一段代码: #include <stdio.h> typedef struct big_thing { char buf[128]; }big_thing; big_thing return_test() { big_thing b; b.buf[0]=0; retutn b; } int main(int argc, char *argv[]

C++构造函数、拷贝构造函数、赋值运算符漫谈(三)——NRV

// 首先看下面一段程序: class X { public: X() { cout<<"X()"<<endl; }; X(int v):val(v) { cout<<"X(int)"<<endl; } X(const X& x) { cout<<"X(const X& x)"<<endl; } X& operator=(const X&) {

拷贝构造函数和拷贝赋值运算符的调用问题

问题描述 拷贝构造函数和拷贝赋值运算符的调用问题 假设有如下类:class HasPtr{public: HasPtr(const string &s): ps(new string(s))i(0){} HasPtr(const HasPtr &hp){ ps=new string(*hp.ps); i=hp.i; } HasPtr(const char *s):ps(new string(s))i(0){} HasPtr & operator=(const HasPtr &

详解C++ 拷贝构造函数和赋值运算符_C 语言

本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义,但是也没有显式的删除),编译器会自动的隐式生成一个拷贝构造函数和赋值运算符.但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算. class Person { public: Person(const Person& p) = dele

c++怎样让返回对象的函数不调用拷贝构造函数

  我们知道拷贝构造函数有两种"默默"的方式被调用 1. 想函数传入 值参数 2. 函数返回 值类型 今天我们讨论函数返回值类型的情况. 得到结论是 1. 当对象有拷贝构造函数(系统为我们生成.或者我们自己写拷贝构造函数)可以被隐式调用时,函数返回时会使用拷贝构造函数. 2. 当对象的拷贝构造函数声明成为explicit(不能被隐式调用时),函数返回时会使用move构造函数. 先看开始的代码. #include <iostream> #include <memory&

C++友元函数与拷贝构造函数详解_C 语言

一.友元函数 1.友元函数概述: (1)友元函数是定义在一个类外的普通函数. 友元函数和普通函数的定义一样;在类内必须将该普通函数声明为友元. (2)友元函数不是成员函数. 不能通过对象来调用,而是直接调用;友元函数可以访问类的公有.受保护以及私有成员,但是必须通过对象.对象指针或者对象引用来访问. 2.友元函数的声明: friend 返回值类型 函数名(参数表); 在类中只需要将这个声明放置在公有部分即可. class Point { double x, y; public: Point(){

php中拷贝构造函数、赋值运算符重载_php技巧

对象的赋值与复制: 赋值:通过" = "运算符重载User a(10),b;b = a;复制:调用复制构造函数User b;User a(b);或者User a = b;//相当于User a(b);与赋值的区别,赋值是对一个已经存在的对象进行赋值(已经实现定义了被赋值的对象),而复制是从无到有建立一个新的对象,并使它与已有的对象相同.浅复制与深复制: 若对象中有指针成员,在复制时,只会将该指针成员的地址复制给新建立的对象,因此,两个对象中的指针成员都指向了同一块内存区域,在释放时会出