Pointer Wrapper:解引用运算符

时间:2013-04-20 13:24:58

标签: c++ .net pointers c++-cli

我对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获取或设置它指向的值时,使用!aApont具有相同的效果。这是Apont::operator!()目前的定义:

T operator !()
{
    return Valor;
}

正如您在 2。中所看到的(代码中的注释,在相应的错误之前),它不适用于设置值。也许我应该回复参考?创建另一个具有相同名称的运算符,可能在类之外?我尝试了几个选项,然而,我遇到了类似的错误,并且更加困惑。

问题是:如何创建一个行为类似于&的运算符(在本例中为~)和一个行为类似于*的运算符(在本例中为{{1} ,取消引用,但行为类似于!,您可以在下面看到旧的定义?)

Apont::Valor

2 个答案:

答案 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;
}

有人可能有一个解决方法来劫持基本类型的运算符,但我想不出任何简单的解决方案。