C ++:将对象按值传递给同一类的成员函数
Posted
技术标签:
【中文标题】C ++:将对象按值传递给同一类的成员函数【英文标题】:C++: Passing objects by value to a member function of the same class 【发布时间】:2018-04-01 07:01:04 【问题描述】:我是 C++ 的初学者,我刚刚开始学习 OOP。在下面的程序中,我添加了相同类的对象并显示了结果。但是,我无法理解这样一个事实,即如果我按值将对象传递给函数,那么调用函数中的变化是如何反映的。 addNumbers()
函数需要 Complex 类的两个对象,用于调用函数的对象 (c3.addNumbers(c1, c2)
) 被隐式传递给函数,但 c3.real
和 c3.imaginary
的值如何在调用中受到影响函数,因为addNumbers()
无法访问它们在内存中的“位置”。任何帮助将不胜感激!
提前致谢!
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;
【问题讨论】:
【参考方案1】:当您调用c3.addNumbers(c1, c2))
时,addNumbers
会隐式接收到c3
的指针,而不是c3
的副本。这个指针可以明确地与this
关键字一起使用。
所以你的函数可以这样重写:
void complex::addNumbers(complex c1, complex c2)
this->real = c1.real + c2.real;
this->imaginary = c1.imaginary + c2.imaginary;
这完全等同于您原来的addNumbers
函数。
换句话说:每次在成员函数中使用类成员时,都会在该成员前面添加一个隐式this->
;所以如果member
是一个类成员,那么member
在类成员函数中总是等价于this->member
。
【讨论】:
【参考方案2】:虚数和实数是私有属性,但可以通过成员函数(也称为对象的方法)访问。当c3.addNumbers(c1, c2)语句执行时,会等价于以下两条语句:
c3.real = c1.real + c2.real;
c3.imaginary = c1.imaginary + c2.imaginary
之所以能访问c3.real和c3.imaginary是因为addNymbers()函数是Complex类的成员。
【讨论】:
【参考方案3】:我在您的原始代码中制作了一些 cmets 来解释为什么下面的实数和虚数会受到影响。 (寻找//MABVT)
此外: 我会再提供一个有用的例子让你进一步进步!
评论
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;
对于初学者来说,这应该是相当多的。
一些解释
静态全局与局部运算符重载
阅读主题:http://en.cppreference.com/w/cpp/language/operators
您使用的所有运算符(+、-、*、/、%、+=、-=、...)只是函数,它们是为原始类型预定义的,并由 libstd 为 STD 类型提供。
您可以覆盖/定义它们。
我通过两种方式做到这一点:
静态全局运算符+:
接受两个任意的 Complex 实例并添加它们的组件。 最后创建一个 NEW 实例并使用结果进行初始化。
基本上这只是一个静态函数,它通过以下方式链接到“+” 编译器。
还有:
本地成员运算符+=:
接受 Complex 的另一个实例并将其组件值添加到 调用运算符的实例的组件值:`l += r -> 在 l 上调用,其值将通过添加 r' 的值来修改
必须定义所有操作赋值运算符(+=、-=、*=、/= 等...) 在类中,既不能是全局的,也不能是静态的。
常量类型&
阅读更多关于 const 的信息:https://www.cprogramming.com/tutorial/const_correctness.html
对任何类型实例的常量引用将为您确保两件事:
-
&:你只复制地址,但这样你的函数可能会改变所有的公共值或调用大多数函数。
const:实例不可修改,也无法更改任何内容
这意味着:您不必复制实例(按值传递),而只提供它的地址引用(按引用传递)。通常这会提高性能,尤其是在您绕过大型复杂对象时。
【讨论】:
以上是关于C ++:将对象按值传递给同一类的成员函数的主要内容,如果未能解决你的问题,请参考以下文章