我对C ++很新,并且作为练习(也许最终是.Net实用程序)我正在做一个指针包装器(实际上是在C ++ / CLI中,但这也适用于C ++)。这个指针包装器(称为Apont
)当前的行为就像指针一样,如下面的测试所示,如果标记为 1。和 2。的行被注释出:
int main(array<System::String ^> ^args)
{
double ia = 10; double ip = 10;
double *p = &ip; // pointer analogy
Apont<double> ^a =
gcnew Apont<double>(ia); // equivalent to what's below, without errors
a = ~ia;/* 1. IntelliSense: expression must have integral or unscoped enum type
error C2440: '=' : cannot convert from 'double' to 'Utilidades::ComNativos::Apont<T> ^'
error C2171: '~' : illegal on operands of type 'double'*/
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
ia = 20; ip = 20;
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
*p = 30; // pointer analogy
a->Valor = 30; // does exacly what's below, without errors
!a = 30;/* 2. IntelliSense: expression must be a modifiable lvalue
error C2106: '=' : left operand must be l-value */
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
//a->Dispose();
Console::ReadKey();
p = nullptr;
return 0;
}
我不喜欢这里有两件事,在代码注释中标有 1。和 2。,在有错误的行之前。 operator~
(请参阅 1。)在Apont
之外定义,如下所示:
template<typename T> static Apont<T>^% operator ~(T& valor)
{
return gcnew Apont<T>(valor);
}
我认为这个必须在Apont
之外定义,但我不确定。我无法理解它产生的错误(当然,这些是在使用中,而不是在定义中)。
要设置Apont
实例引用的值,我必须使用属性(标记为 2。的行不起作用,仅在设置用法中出错), Apont::Valor
,相当于使用*p
。我想要做的是当我使用*p
获取或设置它指向的值时,使用!a
对Apont
具有相同的效果。这是Apont::operator!()
目前的定义:
T operator !()
{
return Valor;
}
正如您在 2。中所看到的(代码中的注释,在相应的错误之前),它不适用于设置值。也许我应该回复参考?创建另一个具有相同名称的运算符,可能在类之外?我尝试了几个选项,然而,我遇到了类似的错误,并且更加困惑。
问题是:如何创建一个行为类似于&
的运算符(在本例中为~
)和一个行为类似于*
的运算符(在本例中为{{1} ,取消引用,但行为类似于!
,您可以在下面看到旧的定义?)
Apont::Valor
答案 0 :(得分:1)
如果我正确理解了您的代码,您希望运算符~
返回指针包装器和运算符!
的副本以作为取消引用吗?
在这种情况下,您可以在调用复制构造函数的operator ~
类中定义一元Apont
。如果你想要一个值,operator !
必须确实返回一个引用。
我认为以下c ++代码定义了您要执行的操作(我将Apont
重命名为A
):
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr)
:payload(ptr) {}
A(const A&other)
:payload(other.payload) {}
T& operator !(){
return *payload;
}
T* operator ~(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
PRINT(i);
A<int> a(&i);
!a = 1;
PRINT(i);
A<int> b = ~a;
!b = 2;
PRINT(i);
}
上面代码的输出是:
i = 0
i = 1
i = 2
根据您的评论,您说过您希望运算符!
的行为与包装指针完全相同。您可以这样做,但随后语法会发生变化,您需要取消引用它以分配新值(因为它是一个指针......)。比如:
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr): payload(ptr) {}
// this now behaves like accessing the wrapped pointer directly
T*& operator !(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
int j = 999;
PRINT(i);
A<int> a(&i);
*(!a) = 1; // note the change of syntax here
PRINT(*!a); // and here
!a = &j; // but now you can change the wrapped pointer through the operator
PRINT(*!a);
}
答案 1 :(得分:1)
让我回顾一下新答案的清晰度。
解决!
运算符非常简单,正如我在之前的回答中所说,只需添加引用。
因此,对于运算符~
,目标是使其行为类似于&
运算符,并调用指针包装类的构造函数。
我认为这是不可能的。对于用户定义的对象当然是可能的,但我认为不可能为内置类型重载一元运算符。因此,根据您的喜好,有三种解决方案:
第一个完全符合你的要求,但会破坏原始类型:
#include <iostream>
template<typename T>
struct A {
T* payload;
A()
: payload(NULL){}
A(T *ptr)
: payload(ptr) {}
T& operator !(){
return *payload;
}
};
// this will not work for primary types
template<typename T>
A<T> operator ~(T &b){
return A<T>(&b);
}
struct B{
int test;
};
int main(){
B b; b.test = 4;
A<B> a;
a = ~b; // I think this is what you want
std::cerr << (!a).test << std::endl;
// this does not work
//int i = 4;
//A<int> a;
//a = ~i;
}
第二种解决方案:使用复合赋值运算符。优点是副作用很小,缺点是这不是很直观,可能会打破你想到的漂亮设计。
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
};
template<typename T>
A<T>& operator &=(A<T> &a, T& b){ // should be friend of the above
a.payload = &b;
return a;
}
int main(){
int i = 3;
A<int> a;
a &= i;
std::cerr << !a << std::endl;
}
第三种解决方案:重载基本赋值运算符。这更直观,但有很多副作用:
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
A<T>& operator = (T & b) {
payload = &b;
return *this;
}
};
int main(){
int i = 3;
A<int> a;
a = i;
std::cerr << !a << std::endl;
}
有人可能有一个解决方法来劫持基本类型的运算符,但我想不出任何简单的解决方案。