在c ++类中具有公共属性

Kha*_*anS 12 c++ properties

我如何在C++类中拥有属性,就像在C#类中一样.

我不想有getter和setter方法.

con*_*nio 12

您可以使用类似于Jon建议的解决方案,但使用运算符重载保留普通的C++语义.我稍微修改了Jon的代码如下(解释遵循代码):

#include <iostream>

template<typename T>
class Accessor {
public:
    explicit Accessor(const T& data) : value(data) {}

    Accessor& operator=(const T& data) { value = data; return *this; }
    Accessor& operator=(const Accessor& other) { this->value = other.value; return *this; }
    operator T() const { return value; }
    operator T&() { return value; }

private:
    Accessor(const Accessor&);


    T value;

};

struct Point {
    Point(int a = 0, int b = 0) : x(a), y(b) {}
    Accessor<int> x;
    Accessor<int> y;
};

int main() {
    Point p;
    p.x = 10;
    p.y = 20;
    p.x++;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 15;
    std::cout << p.x << "," << p.y << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们重载operator=以保留通常的赋值语法而不是类似函数调用的语法.我们使用cast操作符作为"getter".我们需要第二个版本operator=来允许分配第二种类型main().

现在你可以添加到Accessor的构造函数指针,或者更好的 - 仿函数 - 以任何方式调用getter/setter似乎都适合你.下面的例子假设setter函数返回bool以传达设置新值的协议,并且getter可以在它出路时修改它:

#include <iostream>
#include <functional>
#include <cmath>

template<typename T>
class MySetter {
public:
    bool operator()(const T& data)
    {
        return (data <= 20 ? true : false);
    }
};

template<typename T>
class MyGetter {
public:
    T operator()(const T& data)
    {
        return round(data, 2);
    }

private:
    double cint(double x) {
        double dummy;
        if (modf(x,&dummy) >= 0.5) {
            return (x >= 0 ? ceil(x) : floor(x));
        } else {
            return (x < 0 ? ceil(x) : floor(x));
        }
    }

    double round(double r, int places) {
        double off = pow(10.0L, places);
        return cint(r*off)/off;
    }
};

template<typename T, typename G = MyGetter<T>, typename S = MySetter<T>>
class Accessor {
public:
    explicit Accessor(const T& data, const G& g = G(), const S& s = S()) : value(data), getter(g), setter(s) {}

    Accessor& operator=(const T& data) { if (setter(data)) value = data; return *this; }
    Accessor& operator=(const Accessor& other) { if (setter(other.value)) this->value = other.value; return *this; }
    operator T() const { value = getter(value); return value;}
    operator T&() { value = getter(value); return value; }

private:
    Accessor(const Accessor&);

    T value;

    G getter;
    S setter;

};

struct Point {
    Point(double a = 0, double b = 0) : x(a), y(b) {}
    Accessor<double> x;
    Accessor<double> y;
};

int main() {
    Point p;
    p.x = 10.712;
    p.y = 20.3456;
    p.x+=1;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 15.6426;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 25.85426;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 19.8425;
    p.y+=1;
    std::cout << p.x << "," << p.y << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,如最后一行所示,它有一个bug.返回T&的转换运算符允许用户绕过setter,因为它允许用户访问私有值.解决此错误的一种方法是实现您希望Accessor提供的所有运算符.例如,在下面的代码中我使用了+ =运算符,并且由于我删除了转换引用返回引用,我必须实现operator+=:

#include <iostream>
#include <functional>
#include <cmath>

template<typename T>
class MySetter {
public:
    bool operator()(const T& data) const {
        return (data <= 20 ? true : false);
    }
};

template<typename T>
class MyGetter {
public:
    T operator() (const T& data) const {
        return round(data, 2);
    }

private:
    double cint(double x) const {
        double dummy;
        if (modf(x,&dummy) >= 0.5) {
            return (x >= 0 ? ceil(x) : floor(x));
        } else {
            return (x < 0 ? ceil(x) : floor(x));
        }
    }

    double round(double r, int places) const {
        double off = pow(10.0L, places);
        return cint(r*off)/off;
    }
};

template<typename T, typename G = MyGetter<T>, typename S = MySetter<T>>
class Accessor {
private:
public:
    explicit Accessor(const T& data, const G& g = G(), const S& s = S()) : value(data), getter(g), setter(s) {}

    Accessor& operator=(const T& data) { if (setter(data)) value = data; return *this; }
    Accessor& operator=(const Accessor& other) { if (setter(other.value)) this->value = other.value; return *this; }
    operator T() const { return getter(value);}

    Accessor& operator+=(const T& data) { if (setter(value+data)) value += data; return *this; }

private:
    Accessor(const Accessor&);

    T value;

    G getter;
    S setter;

};

struct Point {
    Point(double a = 0, double b = 0) : x(a), y(b) {}
    Accessor<double> x;
    Accessor<double> y;
};

int main() {
    Point p;
    p.x = 10.712;
    p.y = 20.3456;
    p.x+=1;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 15.6426;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 25.85426;
    std::cout << p.x << "," << p.y << std::endl;

    p.x = p.y = 19.8425;
    p.y+=1;
    std::cout << p.x << "," << p.y << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您必须实现您将要使用的所有运算符.


Jon*_*rdy 7

对于像这样的行为,我使用模板化的元访问器.这是POD类型的高度简化:

template<class T>
struct accessor {

    explicit accessor(const T& data) : value(data) {}
    T operator()() const { return value; }
    T& operator()() { return value; }
    void operator()(const T& data) { value = data; }

private:

    accessor(const accessor&);
    accessor& operator=(const accessor&);
    T value;

};
Run Code Online (Sandbox Code Playgroud)

典型用法是这样的:

struct point {
    point(int a = 0, int b = 0) : x(a), y(b) {}
    accessor<int> x;
    accessor<int> y;
};

point p;
p.x(10);
p.y(20);
p.x()++;
std::cout << p.x();
Run Code Online (Sandbox Code Playgroud)

如果您正确设置并启用了优化,编译器通常会内联这些调用.无论采用何种优化措施,它都不会比使用实际的getter和setter更具性能瓶颈.扩展它以自动支持非POD或枚举类型,或允许在读取或写入数据时注册回调是微不足道的.

编辑:如果您不想使用括号,则可以始终定义operator=()隐式强制转换运算符.这是一个可以做到这一点的版本,同时还添加了基本的"发生的事情"回调支持:

进一步编辑:好的,完全错过了有人已经修改了我的代码版本.叹.