这是http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/
的一些代码我一直在调查运营商从几个自学网站和浏览论坛中超载。我问了一个关于使用不同方法重载的问题,我现在明白了。该Q& A链接在How is this returning a value when it has not been defined?
但是,这个方法带参考我不明白。我试图用不同的方式来实现代码,并且已经看到一些不那么复杂的工作方式。
我理解这样做的方法是将类的实例作为操作符函数的参数,操作符函数中的临时实例,并使用=运算符返回这些值。这种方式要复杂得多,我有几个问题就是为什么这种方法有效。
问题在于您下载代码时的措辞,但以下是我提出的三个问题
(问题1)Ceteris parabis,为什么我需要参数中的const关键字?我知道,如果我将变量公开,我不会,但为什么如果有一个朋友类,或者如果代码是在类本身内写的,我是否需要使用const。
(问题2)如果我把朋友功能放在课堂里,我还需要关键词“朋友”为什么?
(问题3)c1和c2类在哪里初始化?有一个对它们的引用,但是在返回之前没有初始化,但是它低于引用。我认为编译时会出错。
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents) { m_nCents = nCents; }
//I know this assigns each
//instance to the private variable m_nCents since it's private.
// Add Cents + Cents
friend Cents operator+(const Cents &c1, const Cents &c2);
//why do we need
//to make this a friend? why can't we just put it inside the class and not
//use the "friend" keyword? also why do I need to make the variables public
//if i remove const from the parameters
int GetCents() { return m_nCents; }
//I know how this is used to return the
// variable stored in m_nCents, in this program it is for cout
};
// note: this function is not a member function!
Cents operator+(const Cents &c1, const Cents &c2)
//where are these references
//actually defined? I do not see c1 or c2 anywhere except in the return, but
//that is below the code that is referencing the class
{
// use the Cents constructor and operator+(int, int)
return Cents(c1.m_nCents + c2.m_nCents);
}
int main()
{
Cents cCents1(6);
Cents cCents2(8);
Cents cCentsSum = cCents1 + cCents2;
std::cout << "I have " << cCentsSum .GetCents() << " cents." << std::endl;
return 0;
}
答案 0 :(得分:4)
以下可能更具说明性:当您计算总和时,您的代码相当于:
Cents cCentsSum = operator+(cCents1,cCents2);
(是的,以上是实际的法律代码)。
这更类似于函数调用,实际上是运算符。引用是参数,因此const Cents& c1
引用cCents1
和const Cents& c2
引用cCents2
。
现在需要实现此免费功能,但您正在访问c1.m_cents
private
。为了实现这一点,您需要将方法声明为friend
,否则您编写的自由函数将产生访问错误。
你仍然需要将它声明为friend
,即使你把它放在了类中,因为运算符是特殊的。编译器看到你的operator +有两个参数,因此它知道这是而不是一个成员函数。它实际上等同于自由函数的代码,只是更紧凑。
最后,您希望这些引用为const
以避免意外修改。考虑一下你是否写道:
Cents operator+(Cents &c1, Cents &c2)
{
return Cents(c1.m_nCents += c2.m_nCents);
}
请注意+=
而不是+
,它会修改c1
的值。在您的示例中,这意味着在之后调用
Cents cCentsSum = cCents1+cCents2;
cCents1
的值将被修改。当然不可取。通过使参数const引用,您要求编译器确保上述情况不会发生,并在编译代码时报告为错误。
答案 1 :(得分:3)
const的一大优点是它意味着它们不会改变,因为使用C ++编译器可以看到所有类型,如果它不可变但是const知道只有const方法可以被调用等等,ad它可以强制执行const方法不会改变那种状态(编译那些类的实现时)
当你使用const任何东西时,编译器可以确定它不会改变(除非可变,但我们忽略它),所以它可以对代码做一些漂亮的优化。
如果每个函数参数都是const且不可变,那么编译器知道它何时使用那些函数,该对象在调用之前和之后处于相同的状态,因此寄存器中的任何值都不需要刷新(尽管寄存器分配很久以后。)
Const很好,如果有人是“总妓女”,这是一种恭维。
所以回答这个问题,私有意味着只有朋友和班级才能改变状态,const意味着没有人可以(除非可变)。
很难给出一个例子,因为优化只发生在编译器可以在/ a标准之后通过完全相同的程序状态进行PROVE时,就好像它写了你写的那样。
class State {
private:
bool state;
public:
State() {
state = false;
}
bool getState() {
return state;
}
void alterState() {
state = !state;
}
};
void doSomething(State&);
int main(int,char**) {
State state;
bool before = state.getState();
std::cout<<"The state is: "<<before<<"\n";
doSomething(state);
bool after = state.getState();
std::cout<<"The state is: "<<after<<"\n";
return 0;
}
假设doSomething在另一个文件中定义。
当我们发现编译器之后必须对state.getState()进行调用,因为它无法证明在==之后。
但是,如果我们有:
void doSomething(const State&);
int main(int,char**) {
State state;
bool before = state.getState();
std::cout<<"The state is: "<<before<<"\n";
doSomething(state);
bool after = state.getState();
/*compiler can do after=before because bool
is a type that will produce the same result
as if it actually did the getState*/
std::cout<<"The state is: "<<after<<"\n";
return 0;
}
这表明const是多么伟大。编译器知道doSomething采用常量(引用a)状态,并且由于状态没有可变字段,因此它知道状态状态因为该调用而无法改变。如果它们都在同一个文件中,它可能会看到doSomething做了什么(它没有改变状态假设)并意识到它无论如何都可以做到,现代的非常非常聪明。您希望为编译器提供每次优化的机会。
传递const引用意味着一切都可以看,但不能触摸,因此编译器必须处理的任何值都是有效的,因为它是const,它们不能改变。
记住这个: 所有优化都好像从未发生过一样,程序状态是相同的,没有秒表或调试器或反汇编程序,你无法分辨编译器做了什么。它可以优化一些变量(如果它可以证明没有副作用),打印该变量虽然会阻止它这样做,编译器将始终按照标准执行完全键入的操作