我是C ++的新手,我正在学习它。我有几个问题..
void DoSomething(const Foo& foo)和 void DoSomething(Foo foo)之间有什么区别?如果我们没有指定&那么Foo的实例将通过值(不是引用)传递。它与const +&相同。在参数中,除了在编译时没有检查。那么,为什么有const +&没有&成为争论的最佳实践和const?
在C#中,传递对象是“通过引用”,但似乎不是在C ++中。
我正在阅读的书中说成员函数通过引用传递隐式参数..
任何人都可以给我隐式参数的样本并通过引用吗?我知道如果我们想通过引用传递对象,我们需要使用& (例如Foo(Person& p))但是为了隐式参数,C ++如何通过引用传递对象?我读到C ++中的隐式参数就像Contructor(string str):strMemberVariable(str){} ...
数组是唯一通过C ++引用传递的数组吗?
为什么我不能在Foo类中使用 Foo fInstance ?
示例:
class Foo {
public:
Foo() { }
Foo(const Foo& f) : fInstance(f) { }
Foo fInstance;
};
提前致谢。
答案 0 :(得分:10)
1虚空DoSomething(const Foo& foo)和
void DoSomething(Foo foo)
之间有什么区别?如果我们不指定&那么Foo
的实例将通过值(不是引用)传递。它与const +&相同。在参数中,除了在编译时没有检查。那么,为什么有const +&没有&成为争论的最佳实践和const?在C#中,传递对象是“通过引用”,但似乎不是在C ++中。
按重要性顺序存在一些差异:
Foo
,则需要通过引用Foo
是基类,则应通过引用获取它,以便用户可以使用派生类调用函数const
对它的引用2我正在阅读的书中说成员函数通过引用传递隐式参数..
任何人都可以给我隐式参数的样本并通过引用吗?我知道如果我们想通过引用传递对象,我们需要使用& (例如Foo(Person& p))但是为了隐式参数,C ++如何通过引用传递对象?我读到C ++中的隐式参数就像Contructor(string str):strMemberVariable(str){} ...
通过隐式参数,您应该理解this
,即对象本身。它通过引用有效传递,因为您可以在成员函数中修改其状态。
关注Konrad
的注释:请注意this
本身不是通过引用传递的,this
是对象的引用(指针),但是按值传递。您无法根据需要更改对象的内存地址;)
3数组是C ++中唯一通过引用传递的数组吗?
他们不是。您将看到数组元素的更改,但数组(结构)不会更改。
按照FredOverflow
的说法,举例说明:
void fun(int* p, size_t size);
int main(int argc, char* argv[])
{
int array[15];
fun(array, 15);
}
我们不知道fun
会做什么,它可能会更改array
的某些元素,但无论其行为如何,array
仍将是15个整数的数组:内容更改,结构没有。
因此,要更改array
,我们需要另一个声明:
void changer(int*& array, size_t& size);
这样我们就可以改变内容和结构(并传回新的大小)。当然,我们只能使用动态分配的数组调用此函数。
4为什么我不能在Foo类中使用Foo fInstance?
因为那是无限递归。从编译器的角度考虑它,并尝试猜测Foo
的大小。 Foo
的大小是其属性大小的总和,可能还有一些填充和类型信息。此外,对象大小至少为1
,以便可以解决。那么,如果Foo
有一个Foo
,它的大小是多少:)?
通常的解决方案是使用智能指针:
class Foo
{
public:
private:
std::unique_ptr<Foo> mInstance;
};
因为指针的大小不依赖于指向的对象的大小,所以这里没有递归:)
答案 1 :(得分:7)
由于这里有太多误解和彻头彻尾的错误答案,这是我试图纠正这个问题:
之间有何区别?
void DoSomething(const Foo& foo)
和void DoSomething(Foo foo)?
正如其他人所说,第二个代码需要一个副本(通常调用Foo
的复制构造函数)。
那么,为什么有const +&amp;没有&amp;成为争论的最佳实践和const?
其他人已经回答过一些特殊的问题(例如运行时多态性)。这并不能解释为什么它成为最佳实践。这样做的原因很简单,也很丑陋:因为幅度更有效率。想象一下,将矢量或字符串传递给另一个方法 - 或者基本上只是传递任何大数据结构。复制它的成本通常很大,并且可能经常在代码中调用方法 - 事实上,方法通常经常调用,否则代码设计得很糟糕。
另一方面,当您将对象作为const
引用传递时,这是通过指针在内部(通常)实现的。在所有体系结构中,指针都可以始终高效复制。
我正在阅读的书中说成员函数通过引用传递隐式参数..
我觉得这本书错了。类的成员函数隐式地传递一个引用当前对象的this
指针。但是,这是指针,C ++禁止更改它。没有理由通过引用传递它。
数组是C ++中唯一通过引用传递的数据吗?
在C ++中很少传递数组 - 它们通常作为指针传递:
void foo(int[] x) { … }
实际上与
相同void foo(int* x) { … }
编译器将这两个声明视为相同。当您尝试调用这些方法中的任何一个并将其传递给数组x
时,C ++将隐式地将数组转换为指向其第一个元素的指针 - 这称为“衰变”。因此,foo(x)
将成为foo(&x[0])
。
但是,如果给出了它们的大小,那么数组可以通过引用传递:
void foo(int (&x)[4]);
但是再一次,你明确地声明数组是通过引用传递的。
答案 2 :(得分:4)
在C#中,传递对象是“通过引用”,但似乎不是在C ++中。
不,这是错误的,这是一种常见的误解。在C#,VB和Java等语言中,变量总是按值传递(在C#中显式传递为ref
,在VB中显式传递为ByRef
)。
与C ++的不同之处在于变量本身不包含类'对象,它们只包含引用。所以传递给方法的不是对象本身,而是它的引用(但 是通过值传递的)。
差异非常重要。如果C#使用通过引用传递,则以下代码将打印不同的结果:
void foo(string s) {
s = "world";
}
string s = "hello";
foo(s);
Console.WriteLine(s); // prints "hello"
答案 3 :(得分:4)
为什么我不能在Foo类中使用Foo fInstance?
因为从概念上讲,Foo的一个对象需要无限量的空间。从技术上讲,类型Foo在Foo的定义中是不完整的。
你可能想要的是指向Foo作为成员的指针。
答案 4 :(得分:1)
void DoSomething(const Foo& foo)
和void DoSomething(Foo foo)
之间的差异是第一个通过引用传递参数,第二个按值传递。实际差异是:
为了更好地解释#3,请考虑以下情况:
std::string global_string;
void foo(const std::string &str)
{
if (str.empty())
{
global_string = "whatever";
// is str still empty??
}
}
如果foo被称为foo(global_string)
,那么当您更改global_string
时,这也会更改str
。
答案 5 :(得分:1)
一次一个:
doStuff(Foo f)
表示在调用方法时将在堆栈上创建新的Foo
对象 - AKA by-value 。调用doStuff(const Foo &f)
表示您只是传递一个新引用,对象不重复,您只保留对它的引用。这是传递参数最安全的方法,因为它不涉及复制对象的副本。这称为传递 by-reference ,是最接近Java / C#行为的。
您在谈论哪个隐含参数?
同样,数组(假设它们是std::array
s)可以通过值,指针或引用传递 - 没有单一的行为。正如Konard所提到的,C风格的数组(只不过是内存块)不能按值传递。
答案 6 :(得分:0)
我正在阅读的书中说成员函数通过引用传递隐式参数..
本书讨论的是隐式指针 this ,它被传递给类中定义的每个非静态成员函数。这是因为C ++在类中保存了每个成员函数的副本而不是每个对象,因此该方法应该知道该类应该处理哪个对象。
class FOO{
int x;
void doSomthing(int x);
}
void FOO::doSomething(int x){
x = x;
}
会被编译成类似的东西
void FOO::doSomething(FOO* this, int x){
this->x = x;
}
由于静态函数是类函数而不是对象函数,因此它们不需要创建对象以便被调用,因此它们不应该访问类的非静态字段,因此不能需要一个指向对象的指针。
答案 7 :(得分:0)
通过const引用而不是通过值传递并不是完全接受的“好习惯”。
This blog post解释了原因。
人们倾向于认为const引用更快,但事实是允许编译器在传递值时优化副本,因此传递值是一个很好的默认值(事实上,标准库通常会这样做例如,std::for_each
按值获取两个迭代器,按值获取一个仿函数)
使用const引用的主要原因是对象无法在逻辑上被复制。假设该对象代表一个窗口。您不希望第二个窗口出现在屏幕上,因为您将窗口对象传递给另一个函数,隐式创建副本。
许多对象代表不能或不应该被复制的东西。这些通常具有私有拷贝构造函数,并且必须通过引用或const引用传递给函数。
通过引用传递的另一个原因(const或其他)可能是使用多态对象。假设您有基类B
和派生类D
。您可以安全地将类型D的对象作为const B&
传递,但是将值作为B
类型的对象传递可能会导致切片(仅复制B
子对象,而不是整个D
对象)。
所以一个好的做法是默认传递值 ,但是传递const引用肯定也有它的位置。两者都有语言是有原因的。
答案 8 :(得分:0)
What is the differences between void DoSomething(const Foo& foo) and
虚空DoSomething(Foo foo)?
实际上没有区别,const会阻止你改变'foo'的内容,而传递值也不会影响参数的内容,但是在效果方面,const Foo&amp; foo更有效,因为当对象传递给方法时它不会创建副本。
答案 9 :(得分:0)
虚空之间有什么区别 DoSomething(const Foo&amp; foo)和无效 DoSomething(Foo foo)?
一般来说,后者将深度复制传递的参数(换句话说,它会复制原始的Foo对象)。前者将传递参数的浅拷贝(将其地址复制到不可变的const引用而不是复制实际的Foo对象)。
这两个版本都可以访问传递的Foo对象的成员。它们都不会修改调用者中的Foo对象。如果函数不需要深层复制,那么基本的区别在于前者更有效,因为它避免了深层复制的需要。
任何人都可以给我隐含参数的样本并通过引用吗?我知道如果我们想通过引用传递对象,我们需要使用&amp; (例如Foo(Person&amp; p))但是为了隐式参数,C ++如何通过引用传递对象?我读到C ++中的隐式参数就像Contructor(string str):strMemberVariable(str){} ...
在参数化的一元构造函数(构造函数采用一个参数)的上下文中,它们可以是隐式的(默认的)或显式的。
class Foo
{
Foo(int x) {...}
};
这是隐含的。它允许我们编写如下代码:
Foo foo = 123;
void f(const Foo& x);
f(123);
虽然这是明确的:
class Foo
{
explicit Foo(int x) {...}
};
...并且不会是之前的代码。必须相应地修改先前的代码:
Foo foo(123);
void f(const Foo& x);
f(Foo(123) );
将这些构造函数显式化通常是一个好习惯,除了复制构造函数之外我不会进入这里,因为它更容易参与。
数组是唯一经过的数组 用C ++引用?
我不确定这里有什么问题,但如果这就是你的意思,那么数组不能通过值传递。我们只能将引用/指针传递给数组:
// takes an array of 10 integers
void fn(int(&some_array)[10]);
// takes a pointer to an int array
void fn(int* some_array);
// takes a pointer to an int array (the 10
// literal constant is ignored) and this function
// can likewise take any pointer to int
void fn(int some_array[10]);
为什么我不能在Foo中使用Foo fInstance 类?
这是无限递归的。 Foo存储fInstance,fInstance存储另一个fInstance,依此类推。没有什么可以阻止递归,所以你只需要存储存储对象的对象的对象,等等,直到你的内存不足为止。因此编译器检测到这种情况并且不允许,因为它不会产生合法的运行时行为。也没有办法确定Foo的大小 - 这将是一个无限的值。
答案 10 :(得分:-1)
void DoSomething(Foo foo)
实际上传递了foo和
的副本void DoSomething(Foo& foo)
传递对foo的引用,所以如果你在函数中修改foo,你将修改原来的foo。我希望这是有道理的。
对于数组,数组实际上是指向数组开头的指针,并且该指针被传递(不复制整个数组)。
array[5] = 0;//is the same as :
*(array+5) = 0; //this
答案 11 :(得分:-5)
void DoSomething(const Foo&amp; foo)和void DoSomething(Foo foo)之间有什么区别
如果Foo是原始数据类型,则DoSomething(Foo foo)按值传递对象foo,但如果Foo是用户定义的数据类型,则通过引用传递。但在第二种情况下,如果你改变foo,它会被反射回原始对象,这通常是不可取的。这由DoSomething(const Foo&amp; foo)处理,它通过引用传递foo(因此节省了传递值的额外内存成本),并且仍然没有对foo的DoSomething函数进行写访问。因此,这是一种最佳实践。
有人能给我样品吗? 隐含参数和引用?
成员函数中隐式参数的一个示例是对父对象的引用,即。 this
,在函数的定义中从未提及,但始终可供使用。
数组是唯一经过的数组 用C ++引用?
不,所有用户定义的对象都通过引用传递。