2012-03-01 52 views
1

可以说我有以下几点:这是通过引用还是按价值传递?

class MyClass 
{ 
    // ... 
} 

void doSomething (MyClass instance) 
{ 
    // Is instance passed by reference or by value (copied)? 
} 

void main() 
{ 
    MyClass instance = MyClass(); 

    doSomething(instance); 
} 

doSomething()instance按引用传递?或者这个类是否在内存中复制?或者是其他东西?

+0

幕后发生了什么?整个对象是否在内存中复制? – Cheetah 2012-03-01 21:48:04

+0

你必须看看复制构造函数的作用。 – 2012-03-01 21:49:26

+0

在本例中,你的参数'实例'是由编译器定义的拷贝构造函数构造的。 – 2012-03-01 21:49:46

回答

5

这是通过值传递

void doSomething (MyClass instance) 

这是通过参考

void doSomething (MyClass& instance) 

通过这是通过const引用传递

void doSomething (const MyClass& instance) 

MyClass而且不需要通过构建通过分配。 所以:

MyClass mc=MyClass(); 

实际上是相同的:

MyClass mc; //no parens needed for default constructor (no args). 

编辑: 这是由常量引用传递给const函数,const函数可以在const对象上调用,因为它保证不要修改对象状态。

void doSomething (const MyClass& instance) const 

与许多不太严格的语言不同,Const正确性在C++中被认为是很好的做法。

见我

http://en.wikipedia.org/wiki/Const-correctness

http://www.gotw.ca/gotw/006.htm

+0

除了'doSomething()'方法无法修改'const'关键字之外,还有什么意义呢? – Cheetah 2012-03-01 21:52:39

+0

@Ben它允许临时对象作为参数传递。 – Marlon 2012-03-01 21:53:40

+0

当函数不需要修改刚刚读取的对象的状态时,应该使用Const。你应该把你的函数标记为const(以min为单位添加一个例子),然后可以在对象为const时使用这些函数。 – 111111 2012-03-01 21:53:56

1

如果没有明确说明,则不作为参考。它是有价值的。

以下原型是指通过引用传递参数:

void doSomething (MyClass& instance) 
{ 
    // Is instance passed by reference or by value (copied)? 
    // In this case, by reference 
} 

事实上,在你的情况下,最有可能创造一个新的对象。我说很可能是因为,只要可观察到的行为是相同的,那就不是。但是,理论上,是的,创建一个新的对象用于函数内部。

新对象是通过调用作为参数传递的对象上的复制构造函数创建的。如果你还没有定义一个复制构造函数,那么编译器就会生成一个默认值,它执行浅拷贝。

+0

“我说很有可能是因为,只要可观察到的行为是相同的,它可能不是”>>不能得到它,你能解释一下吗? – 2012-03-01 21:52:23

+0

@ Mr.Anubis编译器可以优化额外的对象。 – 2012-03-01 21:53:34

+0

有没有办法扭转这种情况。我的意思是,是否有任何方法来编写'MyClass',如果没有明确说明,IT是通过引用传递的,而不是通过值传递的? – Cheetah 2012-03-01 21:57:48

1

是的,它被复制。

当您调用doSomething时,会调用MyClass拷贝构造函数来创建一个新实例。

此实例将在doSomething函数期间保持在范围内。当函数结束时,此实例将调用MyClass析构函数。

(请注意,如果您没有编写复制构造函数,则默认为您创建一个。)

因此,如果你添加一个明确的拷贝构造函数和析构函数:

class MyClass 
{ 
    public: 
     MyClass() 
     { 
      std::cout << "MyClass constructor" << std::endl; 
     } 
     MyClass(const MyClass& other) 
     { 
       std::cout << "MyClass copy constructor" << std::endl; 
     } 
     MyClass::~MyClass() 
     { 
       std::cout << "MyClass destructor" << std::endl; 
     } 
} 
void doSomething (MyClass instance) 
{ 
    std::cout << "doSomething method"; 
} 

void main() 
{ 
    MyClass instance = MyClass(); 
    std::cout << "invoking doSomething" << std::endl; 
    doSomething(instance); 
    std::cout << "returned from doSomething" << std::endl; 
} 

这将输出如下:

  • MyClass的构造
  • 调用DoSomething的
  • MyClass的拷贝构造函数
  • doSomething方法
  • MyClass的析构
  • 从doSomething的
  • MyClass的析构函数返回
1

它是为了复制在堆栈上被传递给函数。如果你的类已经达到了一定数量的字节,这可能是非常昂贵的,因为每个实例变量都必须放在堆栈上。在这种情况下,类的行为与普通的c结构不同。

所以可以说你对你有2个整型(我假设32位系统)

class A { 
    int a; 
    int b; 
}; 
当您在主声明它

,堆栈指针为8个字节的下降。 如果你调用your_function(A),C必须将布局类复制到堆栈,以便your_function在被调用后可以访问它。这意味着堆栈指针再次下降8个字节,值从旧值写入,函数被调用。

与2个实例变量这不是什么大不了的事。但是你有一个可以保存结构并且可以说20个整数+虚拟表的类的图像?比我可以是一个非常昂贵的操作。如果通过指针传递,堆栈指针必须仅减少4个字节,将其中的类地址复制并调用该函数。当然更便宜。

你可以自己尝试。只需更改函数内的某个实例变量,并在函数返回后检查,如果第一个类具有新值或函数调用之前的值。这应该给你答案。

在任何情况下,如果这是你想要的,你应该实现一个拷贝构造函数来处理如何拷贝你的变量。

相关问题