c++ “重命名”派生类中的成员变量

iyfjxgzm  于 2022-12-01  发布在  其他
关注(0)|答案(5)|浏览(205)

这个问题可能看起来有点奇怪,但我会试着对用例进行一点辩论。
假设您有一个二维(笛卡尔)域的通用实现,其维度为dim1和dim2,坐标为c1和c2。

struct Field2D {
  struct size_type {
     size_t dim1,dim2;
  };
  struct coordinates {
     size_t c1,c2;
  }
Field2D(size_type const & siz) : size_(siz), data(size_.dim1*size_.dim2) {}
double get(coordinates const & coords) {
  return data_[coords.c1*size_.dim2 + coords.c2];
}
//Other methods
private:
  size_type size_;
  vector<double> data_;
};

你想继承这个类,但是你想更明确地定义坐标的本质。例如,一个字段PositionVersusTime,它的坐标是“x”和“t”,维度是“nx”和“nt”,我想把它的用法

int main(){
   PositionVersusTime::size_type siz;
   siz.nx = 5;
   siz.nt = 2;
   PositionVersusTime myField(siz);
   PositionVersusTime::coordinates coords;
   coords.x = 2;
   coords.t = 0;
   auto out = myField.get(coords);
   return 0;
}

我这样做的原因是,排序可能会根据字段而改变(例如TimeVersusPosition),有时会被用户“忘记”。是否有方法获得类似的行为?或者我应该简单地使用getter(例如,coords.x()= 2)?

wlp8pajw

wlp8pajw1#

不能。你不能在派生类中“重命名”基类成员。这是语言所不允许的。
一个变量在声明的时候就有了它的名字,并且这个名字永远是它的名字。如果你愿意,你可以为它创建别名(引用),或者你可以用任何改变它的名字来命名函数,但是变量的基本名字在声明的时候就已经固定下来了。

txu3uszq

txu3uszq2#

结合其他解决方案并使用继承和引用数据成员,下面是我的解决方案。
请注意Field2D变量类型的细微变化。

struct size_type{
    size_t dim1, dim2;
};

struct PositionVsTime_size_type : public size_type{
    size_t& nx = dim1;
    size_t& nt = dim2;
};

struct coordinates {
    size_t c1,c2;
};

struct PositionVsTime_coordinates : public coordinates{
    size_t& x = c1;
    size_t& t = c2;
};

struct Field2D {
    Field2D(size_type& siz) : size_(siz), data_(size_.dim1*size_.dim2) {}
    double get(coordinates& coords) {
        return data_[coords.c1*size_.dim2 + coords.c2];
    }
    Field2D& set(coordinates& coords, double val){
        data_[coords.c1*size_.dim2 + coords.c2] = val;
        return *this;
    }
    private:
    size_type& size_;
    vector<double> data_;
};

struct PositionVersusTime : public Field2D {
    PositionVersusTime(size_type& siz) : Field2D(siz) {}
};

int main(){
   PositionVsTime_size_type siz;
   siz.nx = 5;
   siz.nt = 2;
   PositionVersusTime myField(siz);
   PositionVsTime_coordinates coords;
   coords.x = 2;
   coords.t = 0;
   myField.set(coords, 5);
   auto out = myField.get(coords);
   cout << out << endl; // will print 5
   return 0;
}
zengzsys

zengzsys3#

你不能在子类中 * 重命名 * 变量,但是只要稍加努力,就完全可以编写你的main代码。
我首先在PositionVersusTime::作用域中创建自己的自定义coordinatessize_type,然后重写PositionVersusTime中的构造函数和get函数,以接受这些新的结构体。
因此,您的PositionVersusTime结构体将如下所示:

struct PositionVersusTime : public Field2D {
    struct size_type { size_t nx, nt; };
    struct coordinates { size_t x, t; };
    PositionVersusTime(size_type const & siz) : Field2D({siz.nx, siz.nt}) { }
    double get(coordinates const & coords) { return Field2D::get({coords.x, coords.t}); }
};

然后,您发布的主代码将如您所期望的那样工作:

int main() {
   PositionVersusTime::size_type siz;
   siz.nx = 5;
   siz.nt = 2;
   PositionVersusTime myField(siz);
   PositionVersusTime::coordinates coords;
   coords.x = 2;
   coords.t = 0;
   auto out = myField.get(coords);
   return 0;
}

在此查看其工作原理:ideone

lndjwyie

lndjwyie4#

不能在派生类中重命名,但可以在派生类中使用对基成员的引用

size_t& x = coordinates::c1;

但是,使用证明人将阻止重新分配,因为不可能重新分配证明人,您必须找到一个解决方案,以防分配。

6za6bjd0

6za6bjd05#

正如这里的注解中提到的,在派生类中使用引用的解决方案可能会有问题,因为它可能会创建悬空引用。
你想避免这种情况。
而不是:

struct size_type{
    size_t dim1;
};

struct PositionVsTime_size_type : public size_type{
    size_t& nx = dim1;
};

只需执行以下操作:

#define nx dim1

struct size_type{
    size_t dim1;
};

struct PositionVsTime_size_type : public size_type{
};

现在,编译器用 * dim1 * 替换源文件中每次出现的标记 * nx *。
如果 * nx * 不构成标记(出现在注解中、字符串中或作为较长标识符的一部分),则不替换它。

相关问题