casting operator() - 转换为引用并转换为值
casting operator() - cast to reference and cast to value
我的问题涉及标题中给出的主题。
假设我们有一些非常简单的class
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
private:
int m_value;
};
现在我们可以用这个class,它代表int,当然用这个class也没什么意义,只是举个例子。如果想让这个 class 表现得更像一个真正的整数,那么我们应该提供转换运算符(不提及运算符 ==、>、< 等),这是我关心的,因为我可以定义两个运算符:
operator T() {return m_value;}
operator T&() {return m_value;}
一些最简单的示例可以编译并与它们(第一个或第二个)一起工作,因此我们的 class 可以如下所示:
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
operator T(){return m_value;} // casting operator
private:
int m_value;
};
但可以是:
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
operator T&(){return m_value;} // casting operator
private:
int m_value;
};
同样,所以我的问题是这两个哪个合适?当然我不能同时拥有它们,因为编译器无法识别使用哪一个。
自然引用转换似乎更有效,但我不确定它是否始终按应有的方式工作。请以某种方式告诉我,为什么一个操作员比另一个更好?
您的示例中定义的引用转换相当无用 - 您 return 对内部成员的可修改引用,因此违反了封装原则。
如果您 return const 引用代替,这将不是问题。至于 int
和 const int&
之间的选择,这真的不重要——它们在所有情况下的行为都完全相同。
如果您将转换定义为一些重 class,这将更有趣。这样做时,您将看到两个选项 - return by const reference - 但这意味着,不可能在 returned 值上调用非 const 限定方法。如果按值 return,您将承担复制构造函数的费用。选择将由 class 设计决定。
还有一个 returned 引用的生命周期问题 - 但这通常不是问题,除非代码变得非常棘手(您需要将 returned 引用存储为class 的成员遇到了这个问题。
事实上,您两者都需要,稍作调整,编译器就会知道选择哪个。所有的魔力都在于您可以(并且应该在有意义的时候)将成员函数定义为 const
,id est 可从常量对象调用。
因此,您的 Integer
class 应该看起来像
class Integer
{
public:
Integer() : Integer(0) {}
Integer(int number) : m_value(number) {}
Integer(const Integer& other) : m_value(other.value()) {}
int value() const { return m_value; }
operator int() const { return m_value; }
operator int&() { return m_value; }
const Integer& operator=(const Integer& other) { m_value = other; return *this; }
private:
int m_value;
};
此定义将允许 Integer
class 在以下情况下可用:
#include <iostream>
int main()
{
const Integer zero;
const Integer one(1);
Integer counter;
counter = zero + one;
std::cout << "counter: " << counter << std::endl;
counter++;
std::cout << "counter: " << counter << std::endl;
for (Integer i=0 ; i < counter ; ++i)
{
std::cout << "i: " << i << std::endl;
}
return zero;
}
编译 & 运行: g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
输出:
counter: 1
counter: 2
i: 0
i: 1
我同意以上两个答案。人们应该总是倾向于尽量减少直接操纵一个表示的函数的数量。
对象并通过引用公开相同的对象(为什么在上面的两个答案和评论中也有解释)。当确实需要访问表示时,例如运算符+ =,则可以通过固有地修改值来实现他们在 class 本身的第一个参数。
可以在 class 之外定义仅根据其参数值生成新值的运算符,例如 +,并在其实现中使用基本运算符。
class complex{
double re,im;
public:
complex& operator+=(complex a);//needs access to representation.
};
complex operator+(complex a,complex b)
{
complex r=a;
return r+=b; //access representation through +=
}
现在来到你的运营商,类型转换,你真的需要访问表示吗?首先,我们什么时候需要实现类型转换?举个简单的例子:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
};
class Dollars
{
private:
int m_nDollars;
public:
Dollars(int nDollars=0)
{
m_nDollars = nDollars;
}
// Allow us to convert Dollars into Cents
operator Cents() { return Cents(m_nDollars * 100); }
};
根据我的说法,这里我们不需要访问表示,也不需要通过引用 return。
上面的所有例子都处理了一个在 size.But 中非常小的对象,当处理重对象时,复制操作确实可能非常昂贵,这取决于程序员 decide.If 我们想要为了避免复制成本,我们可以传递参考和 return 参考但是...
对结果的引用将作为
引用 return 值,return 值不能是
自动变量.
由于一个运算符经常在一个表达式中使用多次,因此
结果不能作为静态局部变量。
所以,结果通常会分配在空闲 store.Copying
return 值(在执行时间、代码 space 和数据 space 方面)通常比在自由存储上分配和(最终)释放对象更便宜。(#11.6 over.large #C++ Programming Language)
.
这些话题总是有争议的,但我们需要确保的是安全性和无泄漏,这会导致未来更多的控制和更少的痛苦。
我的问题涉及标题中给出的主题。
假设我们有一些非常简单的class
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
private:
int m_value;
};
现在我们可以用这个class,它代表int,当然用这个class也没什么意义,只是举个例子。如果想让这个 class 表现得更像一个真正的整数,那么我们应该提供转换运算符(不提及运算符 ==、>、< 等),这是我关心的,因为我可以定义两个运算符:
operator T() {return m_value;}
operator T&() {return m_value;}
一些最简单的示例可以编译并与它们(第一个或第二个)一起工作,因此我们的 class 可以如下所示:
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
operator T(){return m_value;} // casting operator
private:
int m_value;
};
但可以是:
class Integer{
public:
Integer(int number) : m_value(number) {}
int value(){return m_value;}
operator T&(){return m_value;} // casting operator
private:
int m_value;
};
同样,所以我的问题是这两个哪个合适?当然我不能同时拥有它们,因为编译器无法识别使用哪一个。
自然引用转换似乎更有效,但我不确定它是否始终按应有的方式工作。请以某种方式告诉我,为什么一个操作员比另一个更好?
您的示例中定义的引用转换相当无用 - 您 return 对内部成员的可修改引用,因此违反了封装原则。
如果您 return const 引用代替,这将不是问题。至于 int
和 const int&
之间的选择,这真的不重要——它们在所有情况下的行为都完全相同。
如果您将转换定义为一些重 class,这将更有趣。这样做时,您将看到两个选项 - return by const reference - 但这意味着,不可能在 returned 值上调用非 const 限定方法。如果按值 return,您将承担复制构造函数的费用。选择将由 class 设计决定。
还有一个 returned 引用的生命周期问题 - 但这通常不是问题,除非代码变得非常棘手(您需要将 returned 引用存储为class 的成员遇到了这个问题。
事实上,您两者都需要,稍作调整,编译器就会知道选择哪个。所有的魔力都在于您可以(并且应该在有意义的时候)将成员函数定义为 const
,id est 可从常量对象调用。
因此,您的 Integer
class 应该看起来像
class Integer
{
public:
Integer() : Integer(0) {}
Integer(int number) : m_value(number) {}
Integer(const Integer& other) : m_value(other.value()) {}
int value() const { return m_value; }
operator int() const { return m_value; }
operator int&() { return m_value; }
const Integer& operator=(const Integer& other) { m_value = other; return *this; }
private:
int m_value;
};
此定义将允许 Integer
class 在以下情况下可用:
#include <iostream>
int main()
{
const Integer zero;
const Integer one(1);
Integer counter;
counter = zero + one;
std::cout << "counter: " << counter << std::endl;
counter++;
std::cout << "counter: " << counter << std::endl;
for (Integer i=0 ; i < counter ; ++i)
{
std::cout << "i: " << i << std::endl;
}
return zero;
}
编译 & 运行: g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
输出:
counter: 1
counter: 2
i: 0
i: 1
我同意以上两个答案。人们应该总是倾向于尽量减少直接操纵一个表示的函数的数量。 对象并通过引用公开相同的对象(为什么在上面的两个答案和评论中也有解释)。当确实需要访问表示时,例如运算符+ =,则可以通过固有地修改值来实现他们在 class 本身的第一个参数。
可以在 class 之外定义仅根据其参数值生成新值的运算符,例如 +,并在其实现中使用基本运算符。
class complex{
double re,im;
public:
complex& operator+=(complex a);//needs access to representation.
};
complex operator+(complex a,complex b)
{
complex r=a;
return r+=b; //access representation through +=
}
现在来到你的运营商,类型转换,你真的需要访问表示吗?首先,我们什么时候需要实现类型转换?举个简单的例子:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
};
class Dollars
{
private:
int m_nDollars;
public:
Dollars(int nDollars=0)
{
m_nDollars = nDollars;
}
// Allow us to convert Dollars into Cents
operator Cents() { return Cents(m_nDollars * 100); }
};
根据我的说法,这里我们不需要访问表示,也不需要通过引用 return。
上面的所有例子都处理了一个在 size.But 中非常小的对象,当处理重对象时,复制操作确实可能非常昂贵,这取决于程序员 decide.If 我们想要为了避免复制成本,我们可以传递参考和 return 参考但是...
对结果的引用将作为 引用 return 值,return 值不能是 自动变量.
由于一个运算符经常在一个表达式中使用多次,因此 结果不能作为静态局部变量。
所以,结果通常会分配在空闲 store.Copying
return 值(在执行时间、代码 space 和数据 space 方面)通常比在自由存储上分配和(最终)释放对象更便宜。(#11.6 over.large #C++ Programming Language)
.
这些话题总是有争议的,但我们需要确保的是安全性和无泄漏,这会导致未来更多的控制和更少的痛苦。