假设我有一个简单的向量类vec

#include <iostream>
#include <stdlib.h>

class vec {
public:
    vec() {}
    // Constructor.
    vec(int n) {
        len = n;
        data = new double[len];
    }

    // Destructor.
    ~vec() { delete [] data; }

    // Accessor.
    double & operator[](int i) const {
        check_index(i);
        return data[i];
    }

    // Other methods...
    // ....

protected:
    int len;
    double * data;
    void check_index(int i) const {
        if(i < 0 || i >= len) {
            std::cerr << "Bad access.\n";
            exit(1);
        }
    }
};


现在假设我有一个稀疏结构的特殊类型vector,例如每个偶数索引均为零。称为oddvecoddvec的实例应该与vec类一样声明,但是在下面,由于只有一半的数据为非零,因此内存使用应该高效。

如果索引为偶数,则oddvec类的访问器应返回0,否则返回奇数索引元素(顺序存储)。这有几个问题:


如果索引为偶数,则违反double &返回类型,因为返回了常量值0
当将偶数索​​引元素用作lvalue时,我不清楚如何处理这种情况。例如,在v[0] = 3.0类中不允许使用oddvec,但在vector类中完全可以接受。当使用偶数索引时,我们不能简单地抛出一个错误,因为只要意图是rvalue,偶数索引就可以了。


我如何设计oddvec类的访问器函数,同时保持内存存储效率和从父级继承所有方法?

oddvec的无效示例:

class oddvec : public vec {
public:
    // Constructor.
    oddvec(int n) {
        len = n;
        data = new double[len/2];
    }

    // Accessor (doesn't work!)
    double & operator[](int i) const {
        check_index(i);

        if (i%2 == 0)
            return 0;
        else
            return data[(i-1)/2];
    }
};


编译后:

main.cpp: In member function ‘double& oddvec::operator[](int) const’:
main.cpp:49:20: error: invalid initialization of non-const reference of type ‘double&’ from an rvalue of type ‘double’
             return 0;




使用代理类的工作示例:

我已经实现了以下答案中建议的代理类。


  代理服务器


#ifndef PROXIES_H
#define PROXIES_H

#include <iostream>
#include <stdlib.h>

class proxy {
public:
    proxy(int i, double v, double * d) {
        index = i;
        value = v;
        data  = d;
    }
    void operator=(double rhs) {
        data[index] = rhs;
    }
    friend std::ostream & operator<<(std::ostream & outs, const proxy & p) {
        outs << p.value;
        return outs;
    }
protected:
    int     index;
    double  value;
    double * data;
};

class oddproxy : public proxy {
public:
    oddproxy(int i, int v, double * d) : proxy(i, v, d) {}
    void operator=(double rhs) {
        if (index%2 == 0) {
            std::cerr << "Even entries of oddvec are not assignable.\n";
            exit(1);
        }
        data[index/2] = rhs;
    }
};

#endif



  向量


#ifndef VECTORS_H
#define VECTORS_H

#include "proxies.h"

class vec {
public:
    vec() {}
    // Constructor.
    vec(int n) {
        len = n;
        data = new double[len];
    }

    // Destructor.
    ~vec() { delete [] data; }

    // Accessor.
    proxy operator[](int i) const {
        check_index(i);
        return proxy(i, data[i], data);
    }

    inline int length() const { return len; }

    // Other methods...
    // ....

protected:
    int len;
    double * data;
    void check_index(int i) const {
        if(i < 0 || i >= len) {
            std::cerr << "Bad access.\n";
            exit(1);
        }
    }
};


class oddvec : public vec {
public:
    // Constructor.
    oddvec(int n) {
        len = n;
        data = new double[len/2];
    }

    // Accessor.
    oddproxy operator[](int i) const {
        check_index(i);
        return oddproxy(i, (i%2 == 0) ? 0 : data[i/2], data);
    }
};

#endif



  main.cpp


#include <iostream>
#include "vectors.h"

int main () {
    int N = 5;
    vec V(N);
    oddvec O(N);

    for(int i=0; i < V.length(); i++) {
        V[i] = i;

        if(i%2 != 0) {
            O[i] = i;
        }
    }

    for(int i=0; i < O.length(); i++) {
        std::cout << "V[" << i << "]=" << V[i] << ", "
                  << "O[" << i << "]=" << O[i] << "\n";
    }

    O[0] = 13;

    return 0;
}



  输出


V[0]=0, O[0]=0
V[1]=1, O[1]=1
V[2]=2, O[2]=0
V[3]=3, O[3]=3
V[4]=4, O[4]=0
Even entries of oddvec are not assignable.

最佳答案

您可以使用代理对象来执行此操作。



简单的示例代码:

#include <iostream>
#include <vector>
using namespace std;

class very_odd_vector{
public:
    class only_odd_proxy;
    friend class only_odd_proxy;
    only_odd_proxy operator [](int index);
    int operator [](int index)const{return index%2==0?0:content[index/2];}
    unsigned int size()const{return content.size()*2;}
private:
    vector<int> content{1,3,5,7,9};
};

class very_odd_vector::only_odd_proxy{
public:
   only_odd_proxy(very_odd_vector& vec,int index):vec(vec),index(index){}
   operator int(){return index%2==0 ? 0 : vec.content[index/2];}
   only_odd_proxy& operator =(int value){
      if(index%2==0)
         cout << "BAD OPERATION";//any error you want
      else
         vec.content[index/2] = value;
      return *this;
   }
private:
   very_odd_vector& vec;
   int index;
};

auto very_odd_vector::operator [](int index)->only_odd_proxy{return only_odd_proxy(*this,index);}

int main(){
   very_odd_vector v;

   cout << "reading value\n";
   for(int i=0;i<v.size();++i)
      cout << v[i] <<'\n';

   cout << "writting value\n";
   for(int i=0;i<v.size();++i){
      cout << i << ':';
      v[i]=10;
      cout << '\n';
   }

   cout << "reading value\n";
   for(int i=0;i<v.size();++i)
      cout << v[i] <<'\n';
}




编辑问题的更新部分:

我认为这堂课将更适合您的需求。

//Both base and inherit class return this class
class maybe_readonly_proxy {
public:
    maybe_readonly_proxy(double* data, bool readonly):readonly(readonly),data(data){}
    maybe_readonly_proxy& operator=(double rhs) {
        if(readonly){/*whatever error*/}
        else {*data = rhs;}
        return *this;
    }
    operator double()const{return *data;}
private:
    bool readonly;
    double * data;
};


您可能需要一个变量来包含只读(在这种情况下为0)值,或修改operator double()检查只读状态



或者只是分别实现getset方法并且不使用此代理可能是另一种选择。

关于c++ - 为具有稀疏成员数据的继承类编写访问器方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39917681/

10-10 08:09