在C语言中,对象和指向对象的指针有什么区别?

发布于 2024-10-23 18:36:56 字数 293 浏览 2 评论 0原文

在java和objective-c中,代表对象的变量通常是指向该对象的指针。然而,在 C++ 中,非指针类型保存对象似乎很常见。两者有什么区别?

如果我将一个结构作为参数传递给函数,我相信我是按值传递的,这意味着我实际上是在内存中创建一个新的结构,并且在其传递到的函数内对该结构的更改不会影响“函数外部的“source”结构。但是,如果我将指针传递给结构,则仍然只有一个原始结构,并且对指针引用的结构的更改对于任何知道该结构的代码都是可见的。我有这个权利吗?

那么,物体之间有什么区别吗?当我将非指针对象传递给函数时,整个对象是否会被复制?

In java and objective-c, a variable representing an object is generally a pointer to that object. However, it seems that in C++, it's common to have non-pointer types hold objects. What's the difference between the two?

If I pass a struct as an argument to a function, I believe I'm passing by value, meaning I'm actually creating a new struct in memory, and changes to that struct inside the function its passed to won't affect the "source" struct outside the function. However, if I pass a pointer to a struct, there's still only one original struct, and changes to the struct referenced by the pointer will be visible to any code which is aware of this struct. Do I have that right?

So, is there any difference with objects? When I pass a non-pointer object to a function, does the entire object get copied?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

会傲 2024-10-30 18:36:56

正是如你所说。

当您按值传递对象时,会调用其复制构造函数来生成将在函数内部使用的此类对象的新实例。对此类新对象所做的更改不会反映到原始对象1

与结构一样,默认的复制构造函数仅对原始对象进行浅表复制 - 即,其字段被复制2到新实例;在许多情况下,这是不可取的(例如,如果对象包装指针/另一个资源),因此有些类可以重新定义复制构造函数或完全禁用它。最后这些类的对象只能通过指针或引用传递。

如果对象比指针(大小)大,或者通常如果它们的复制构造函数不“便宜”,则按值传递对象的成本可能会很高。另一方面,与指针相比,按值传递具有通常的优点,即不必指定指针所有权,让被调用者对对象执行任何它想要的操作等。

请注意,按值传递对象会杀死多态性。这是因为按值接收对象的函数接收具有精确大小和类型的静态类型对象,因此任何传递派生类对象的尝试都将导致对象切片(调用基类的复制构造函数,即默认情况下仅复制基类中可用的字段)。

这就是为什么传递对象的首选方法通常是通过 const 引用的原因。这有几个优点:

  • 不涉及副本;被调用者将看到的对象将与调用时指定的对象完全相同;
  • 由于 const 限定符,无法对原始对象进行任何更改;
  • 然而,如果被调用者需要更改对象的副本,它仍然可以根据引用自行构造一个副本;
  • 没有尴尬的指针语法;
  • 保留了多态性,因为在幕后我们实际上传递了一个指针;
  • 关于对象所有权没有什么大的疑问:关于引用的一般规则是它们由调用者拥有。

  1. 就对象的“原始字段”而言;当然,如果原始对象和副本继续共享指向同一资源的指针/句柄,对一个对象的某些修改可能会影响另一个对象。

  2. 原始类型(通常是 POD)按位复制,而非 POD 类型则调用复制构造函数。

It's exactly as you said.

When you pass an object by value, its copy constructor is invoked to produce a new instance of such object that will be used inside the function. The changes done to such new object won't be reflected to the original one1.

As with structures, the default copy constructor just does a shallow copy of the original object - i.e., its fields are copied2 to the new instance; in many cases this is not desirable (e.g. if the object wraps a pointer/another resource), so there are classes which redefine the copy constructor or disable it completely. Objects of these last classes can only be passed by pointer or reference.

Passing objects by value can be costly if they are bigger than a pointer (in size) or in general if their copy constructor isn't "cheap". On the other hand, in comparison to pointers, the pass-by-value yields the usual advantages of not having to specify the pointer ownership, letting the callee do whatever it wants with the object, etc.

Notice that passing an object by value kills the polymorphism. This because a function receiving an object by value receives a statically typed object, with a precise size and type, so any attempt to pass an object of a derived class will result in object slicing (the copy constructor for the base class is called, that by default just copies the fields that are available in the base class).

This is the reason why often the preferred method of passing objects is by const reference. This yields several advantages:

  • no copies involved; the object that the callee will see will be exactly the one specified at the moment of the call;
  • no changes to the original object can be made, thanks to the const qualifier;
  • if however the callee needs to change a copy of the object, it can still construct a copy by itself from the reference;
  • no awkward pointer syntax;
  • polymorphism preserved, since behind the scenes we're actually passing a pointer;
  • no big doubts about object ownership: the general rule about references is that they are owned by the caller.

  1. As far as the "raw fields" of the object are concerned; naturally if the original object and the copy continue to share a pointer/handle to the same resource some modifications to one may affect the other.

  2. Primitive types (and in general PODs) are copied bitwise, while the copy constructor is called for non-POD types.

绻影浮沉 2024-10-30 18:36:56

差异主要与对象在内存中的分配位置有关。例如:

int main() {
    MyObject x;   //allocates space for an instance of MyObject on the stack
    MyObject* y;  //allocates space for a pointer on the stack
    MyObject* z = new MyObject();  //allocates space for a pointer on the 
                                   //stack and an object instance in the heap and
                                   //sets the pointer to point to the new instance
    MyObject* a = &x;  //allocates space for a pointer on the stack and 
                       //makes it point to 'x'
    ...
}

int someFunc(MyObject byValue, MyObject* byReference) {
   //the 'byValue' parameter will be passed by creating a copy of the 
   //entire source object on the stack (can be quite expensive for 
   //complex object types)

   //the 'byReference' parameter will be passed by creating a 
   //copy of the source pointer on the stack and setting it to 
   //point to the source object in memory
}

The difference mostly has to do with where in memory an object is allocated. For instance:

int main() {
    MyObject x;   //allocates space for an instance of MyObject on the stack
    MyObject* y;  //allocates space for a pointer on the stack
    MyObject* z = new MyObject();  //allocates space for a pointer on the 
                                   //stack and an object instance in the heap and
                                   //sets the pointer to point to the new instance
    MyObject* a = &x;  //allocates space for a pointer on the stack and 
                       //makes it point to 'x'
    ...
}

int someFunc(MyObject byValue, MyObject* byReference) {
   //the 'byValue' parameter will be passed by creating a copy of the 
   //entire source object on the stack (can be quite expensive for 
   //complex object types)

   //the 'byReference' parameter will be passed by creating a 
   //copy of the source pointer on the stack and setting it to 
   //point to the source object in memory
}
说不完的你爱 2024-10-30 18:36:56

在 C++ 中,变量它所代表的变量。它是内存中实际位置的实际对象。

但是,您可以选择让这样的变量代表指针,在这种情况下,它会说“嘿,我是我,我指着那边!您想要的对象不在这里,它在那里。是的,走吧,到那里去!”

除非您明确使用 C++ 的“引用类型”(我怀疑您没有这样做),否则您传递的所有参数都是按值传递的。

In C++, a variable is the variable that it is representing. It is the actual object in memory, at the actual location.

However, you can choose to make such a variable represent a pointer instead, in which case it'll say "Hey, I'm me, I am pointing over there! The object you want isn't here, it's THERE. Yes, there! Go on, get there!".

Unless you're explicitly using C++'s "reference type", which I suspect you're not, then ALL arguments you pass are by value.

泪痕残 2024-10-30 18:36:56

第二段和第三段中的问题的答案都是“是”。更具体地说,如果您按值将对象传递给函数,该函数将收到该对象的副本(由复制构造函数创建)。

The answers to the questions in your second and third paragraph are both "yes". More specifically, if you pass an object to a function by value, the function will receive a copy of that object (created by the copy constructor).

岁月染过的梦 2024-10-30 18:36:56

当您按值将对象传递给函数时,它会通过其类的复制构造函数进行复制。如果您尚未定义复制构造函数,则编译器将提供一个默认的复制构造函数(除非您采取特殊步骤来避免这种情况),这相当于手动复制成员。

实际上,首选的做法通常是传递 const 引用,而不是指针或对象本身。

(您可能想知道,实际上 struct 只是一个 class,其成员默认为 public;特别是,结构可以让用户定义的复制构造函数也不一定只是普通的惰性数据。)

When you pass an object to a function by value, it's copied by means of its class's copy constructor. If you haven't defined a copy constructor, there'll be a default one supplied by the compiler (unless you take special steps to avoid that), which is equivalent to copying the members by hand.

The preferred thing to do is often actually to pass a const reference rather than either a pointer or the object itself.

(You might want to be aware that actually a struct is just a class whose members are public by default; in particular, structs can have user-defined copy constructors too. A struct is not necessarily just plain inert data.)

朕就是辣么酷 2024-10-30 18:36:56

你有这个权利。

确实,这就是它的工作原理。指针存储变量的内存地址。

当您将函数的指针(指向对象)作为参数传递时,这意味着函数将可以通过其内存地址访问该对象,而不是在堆栈上创建新对象。

检查此线程< /a> 有关指针的更多信息。

You have that right.

Indeed, that's how it works. A pointer stores the memory address of a variable.

When you pass a pointer (to an object) for a function as a parameter, it means that function will have access to that object through it's memory address instead of a new object being created on the stack.

Check this thread for more info on pointers.

半世蒼涼 2024-10-30 18:36:56
  • 指针存储内存地址。
  • 变量存储一个值。

前任:

Player * a; // Allocated an int value to stored an address, you will able to access to value at that address by a -> but you have to allocated it and free when it done

Player a; // Allocated a block of memory that size equal = Player size.
  • A pointer stores an memory address.
  • A variable stores a value.

Ex:

Player * a; // Allocated an int value to stored an address, you will able to access to value at that address by a -> but you have to allocated it and free when it done

Player a; // Allocated a block of memory that size equal = Player size.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文