C ++:按值将对象传递给同一类的成员函数 [英] C++: Passing objects by value to a member function of the same class

查看:71
本文介绍了C ++:按值将对象传递给同一类的成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C ++的初学者,我才刚刚开始学习有关OOP的知识。在以下程序中,我添加了相同类的对象并显示了结果。但是,我无法理解以下事实:如果我按值将对象传递给函数,那么更改如何反映在调用函数中。 addNumbers()函数需要Complex类的两个对象以及用于调用该函数的对象( c3.addNumbers(c1,c2) )隐式传递给函数,但 c3.real c3.imaginary 在调用函数中受到影响,因为 addNumbers()无法访问其在内存中的位置。

I'm a beginner in C++ and I've just started learning about OOP. In the following program I've added objects of the same classes and displayed the result. However, I'm not able to understand the fact that if I pass the objects to the function by value then how is the change reflected in the calling function. The addNumbers() function expects two objects of the class Complex and the object which is used to invoke the function (c3.addNumbers(c1, c2)) is implicitly passed to the function but how are the values of c3.real and c3.imaginary affected in the calling function since addNumbers() has no access to their "location" in the memory. Any help will be appreciated!

预先感谢!

class complex {
private:
    int real;
    int imaginary;

public:
/* Using member initializers to assign values to members */    
    complex()
        : real(0)
        , imaginary(0)
    {}

    void readData(int x, int y);

    void printData();

    void addNumbers(complex, complex);
};     

void complex::readData(int x, int y)
{
    real      = x;
    imaginary = y;
}

void complex::printData()
{
    cout << real << "+" << imaginary << "i" << endl;
}   

void complex::addNumbers(complex c1, complex c2)
{
    real      = c1.real + c2.real;
    imaginary = c1.imaginary + c2.imaginary;
}

int main(void)
{
    complex c1, c2, c3;
    c1.readData(-5,17);
    c2.readData(11,7);
    c3.addNumbers(c1,c2);
    c3.printData();

    return 0;
}


推荐答案

我在您的原始代码在下面解释了为何影响实数和虚数的原因。 (寻找// MABVT)

I made a few comments in your original code to explain why real and imaginary are affect below. (Look for //MABVT)

另外:
我将提供另一个有用的示例,供您进一步发展!

In addition: I will provide another useful example for you to progress further!

审阅

class complex {
private:
    int real;
    int imaginary;

public:
    /* Using member initializers to assign values to members */    
    complex()
        : real(0)
        , imaginary(0)
    {}

    void readData(int x, int y);

    void printData();

    // MABVT: You provide two complex numbers which you want to add 
    //        together!
    void addNumbers(complex, complex);
};     

void complex::readData(int x, int y)
{
    real      = x;
    imaginary = y;
}

void complex::printData()
{
    cout << real << "+" << imaginary << "i" << endl;
}   

void complex::addNumbers(complex c1, complex c2)
{
    // MABVT: Use c1.component and c2.component, add them up and store them 
    //        in this class' instance.
    real      = c1.real      + c2.real;
    imaginary = c1.imaginary + c2.imaginary;

    // MABVT: c3.real and c3.imaginary are affected at this exact location
    //        since you overwrite the values with the addition-results.
    //        Since the function addNumbers(complex, complex) is invoked
    //        on the complex instance 'c3', real and imaginary of c3 are 
    //        known in this context, and consequently you can use them.
    //
    //        To attach to your statement that the c3 instance's pointer is 
    //        implicitly passed: 
    //        Yes it is passed as the first parameter invisibly as 
    //         'complex* this'
    //
    //        So you could also write:
    //          this->real = c1.real + c2.real; (see the use of this?)
}

int main(void)
{
    complex c1, c2, c3;
    c1.readData(-5,17);
    c2.readData(11,7);
    c3.addNumbers(c1,c2);
    c3.printData();

    return 0;
}

替代

// Example program
#include <iostream>
#include <string>

class Complex { // Give class names capital first letter
private:
    int m_real;      // Just a recommendation: I'd like to be able to distinguish parameter for member in the identifier already!
    int m_imaginary; // Just a recommendation: I'd like to be able to distinguish parameter for member in the identifier already!

public:
    /* Using member initializers to assign values to members */    
    inline Complex()   // Inline it, if you define this class in a header and reuse it multiple times...
        : m_real(0)
        , m_imaginary(0)
    {}

    // Provide initializing constructor to be able to construct 
    // a complex number quickly. Replaces your readData(...);
    inline Complex(
        int inRealPart,
        int inImaginaryPart)
        : m_real(inRealPart)
        , m_imaginary(inImaginaryPart)
    {}

    // Getters to read the values
    inline int real()      const { return m_real; }
    inline int imaginary() const { return m_imaginary; }

    void printData();

    // Local assignment-add operator to add another complex
    // to this specific instance of complex and modify the internal
    // values. Basically what you did as the second part of addNumbers.
    Complex& operator+=(const Complex& r);
};     

void Complex::printData()
{
    std::cout << m_real << "+" << m_imaginary << "i" << std::endl;
}   

// Member add-assign operator definition adding this instance and another instance 'r' by adding up the values and storing them in the instance this operator is called on.
Complex& Complex::operator +=(const Complex& r) 
{ 
    std::cout << "Local" << std::endl;

    this->m_real      += r.real();
    this->m_imaginary += r.imaginary();

    return *this;
}

// Static global operator+ definition, taking two values and creating a 
// third, NEW one initialized with the results.
// This was the first part of addNumbers
static Complex operator+(const Complex& l, const Complex& r) { 
   std::cout << "Static Global" << std::endl;

   return Complex(
            (l.real()      + r.real()), 
            (l.imaginary() + r.imaginary())
          );
}

int main(void)
{ 
    // Same as before
    Complex c1(-5, 17);
    Complex c2(11, 7);
    Complex c3(1, 2);

    // Test output
    c1.printData();
    c2.printData();
    c3.printData();

    std::cout << std::endl;

    Complex  c3 = (c1 + c2);           // Calls static global and c3 is overwritten with the result. Exactly like your addNumbers call
    c1 += c2;                          // instance local, will change c1's internal values ( see print out below )
    Complex  c5 = ::operator+(c1, c2); // Static global, c5 is initialized with the result. Exactly like your addNumbers call

    std::cout << std::endl;

    c1.printData();
    c2.printData();
    c3.printData();
    c5.printData();

    return 0;
}

对于初学者来说,这应该是很多。

This should be quite much for you as a beginner.

一些解释

静态全局操作符与本地操作符重载

阅读以下主题: http://zh.cppreference.com/w/cpp/language/operators

您使用的所有运算符(+,-,* ,/,%,+ =,-=,...)只是为基本类型预定义的函数,由libstd为STD类型提供。

All the operators you use (+, -, *, /, %, +=, -=, ...) are just functions, which are predefined for primitive types and provided by libstd for STD types.

您可以

我这样做有两种方式:


静态全局运算符+:

接受两个任意的Complex实例并添加其组件。
最后,将创建一个NEW实例并使用结果进行初始化。

Accepts two arbitrary Complex instances and adds their components. Finally a NEW instance is created and initialized with the results.

基本上,这只是一个静态函数,通过$ b $链接到 +

Basically this is just a static function, which is linked to "+" by the compiler.

并且:


本地成员运算符+ =:

接受另一个Complex实例,并将其组件值添加到
实例的组件值中。运算符被调用:`l
+ = r->调用l,其值将通过添加r'的值进行修改。

Accepts another instance of Complex and adds its component values to the component values of the instance the operator is called on: `l += r -> Called on l, whose values will be modified by adding the values of r'

所有op-赋值运算符(+ =,-=,* =,/ =等)必须在类中定义
,并且不能为全局或静态。

All op-assignment operators (+=, -=, *=, /=, etc...) must be defined within the class and can neither be global, nor static.

const Type&

阅读有关const的更多信息: https://www.cprogramming.com/tutorial/const_correctness.html

Reading with much more info on const: https://www.cprogramming.com/tutorial/const_correctness.html

常量引用任何类型的实例将为您确保两件事:

Const reference to instances of whatever type will ensure two things for you:


  1. & :您仅复制地址,但是通过这种方式,您的函数可以更改所有公共值或调用大多数函数。

  2. const :实例不可修改且无法更改

  1. &: You only copy the address, but this way you function could change all public values or call most functions.
  2. const: The instance is not modifyable and nothing can be changed

这意味着:您无需复制实例(值),但仅提供其地址参考(按引用传递)。通常,这样做可以提高性能,尤其是当您绕过大型复杂对象时。

In combination that means: You don't have to copy the instance (pass-by-value), but provide it's address reference only (pass-by-reference). Usually that enhances performance, especially once you pass around large and complex objects.

这篇关于C ++:按值将对象传递给同一类的成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆