C++ 在C++;,类成员的参考应为常量或非常量

C++ 在C++;,类成员的参考应为常量或非常量,c++,reference,constants,const-cast,C++,Reference,Constants,Const Cast,考虑下面这个最小的例子 #include <vector> class Data { std::vector<int>& v; public: Data(std::vector<int>& _v) : v(_v) {} Data(const std::vector<int>& _v) : v(_v) {} // error! }; int main() { std::vector<i

考虑下面这个最小的例子

#include <vector>

class Data
{
    std::vector<int>& v;
public:
    Data(std::vector<int>& _v) : v(_v) {}
    Data(const std::vector<int>& _v) : v(_v) {} // error!
};

int main()
{
    std::vector<int> v;
    const std::vector<int> c_v;
    Data d(v);
    Data const_d(c_v);

    return 0;
}
原因对我来说很清楚:const关键字对我在第8行的演员阵容感到不安。问题是:有时我确实需要带有
std::vector
的数据类,但有时需要带有
const std::vector
的数据类。比如有两个类:一个用于读入
数据
,另一个用于读入
数据
。但是,我不喜欢用几乎冗余的函数编写两个数据类。我的问题是:

  • 你能给我一个很好的解决方案来实现我在
    main()
    中尝试做的事情吗?C++11解决方案也非常受欢迎:)
  • 这就是使用
    迭代器
    常量迭代器
    的原因吗

    • 您得到的错误大致如下:

      foo.cpp: In constructor ‘Data::Data(const std::vector<int>&)’:
      foo.cpp:8:44: error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘const std::vector<int>’
      
      另一种选择是使用非引用成员:

      #include <vector>
      
      class Data
      {
          std::vector<int> v;
      public:
          Data(std::vector<int>& _v) : v(_v) {}
          Data(const std::vector<int>& _v) : v(_v) {} // error!
      };
      
      #包括
      类数据
      {
      std::向量v;
      公众:
      数据(std::vector&_v):v(_v){}
      数据(const std::vector&_v):v(_v){}//错误!
      };
      
      const
      -需要在编译时知道数据成员的属性。如果“有时”需要引用
      常量
      向量,有时需要引用非
      常量
      ,则应使用包含公共功能的基本抽象类创建类层次结构,并将其继承到两个
      数据
      类中:
      数据
      常量数据
      Data
      将包含一个非
      const
      向量,
      ConstData
      将包含一个
      const
      向量。这样,您就不会复制任何逻辑,而两个单独的类将包含两个不同的
      常量的引用

      以下是一个例子:

      class AbstractData {
      public:
          // Common functions use vect() and const_vect()
          void common_function1();
          void common_function2();
      protected:
          virtual vector<int>& vect() const = 0;
          virtual const vector<int>& const_vect() const = 0;
      };
      
      class Data : public AbstractData {
          vector<int>& v;
      public:
          Data(vector<int>& _v) : v(_v) {}
      protected:
          vector<int>& vect() const {
              return v;
          }
          const vector<int>& const_vect() const {
              return v;
          }
      };
      
      class ConstData : public AbstractData {
          const vector<int>& v;
          vector<int> temp;
      public:
          ConstData(const vector<int>& _v) : v(_v) {}
      protected:
          vector<int>& vect() const {
              return temp; // You can choose to throw an exception instead
          }
          const vector<int>& const_vect() const {
              return v;
          }
      };
      
      类抽象数据{
      公众:
      //常用函数使用vect()和const_vect()
      void common_function1();
      无效公共_函数2();
      受保护的:
      虚拟向量&vect()常量=0;
      虚拟常量向量&const_vect()常量=0;
      };
      类数据:公共抽象数据{
      向量&v;
      公众:
      数据(向量&_-v):v(_-v){}
      受保护的:
      向量&vect()常量{
      返回v;
      }
      常量向量&常量向量()常量{
      返回v;
      }
      };
      类ConstData:公共抽象数据{
      常数向量&v;
      向量温度;
      公众:
      常数数据(常数向量&_v):v(_v){}
      受保护的:
      向量&vect()常量{
      return temp;//您可以选择抛出异常
      }
      常量向量&常量向量()常量{
      返回v;
      }
      };
      

      请注意,此类层次结构可能需要析构函数和各种副本构造函数,具体取决于用法。

      注意:我目前正在考虑将
      std::vector
      制作为模板,但这是最佳解决方案吗?:)请注意:我在main()中将c_v更改为常量向量。虽然我认为这对你的代码有效。你的代码有效,但我需要
      数据
      类有时具有
      v
      常量。所以这不是解决方案:(在这种情况下,您应该参考@dasblinkenlight的答案。很好的推理!所以我使用模板的想法还不错?在这里使用CRTP而不是虚拟函数可能是一个很好的练习?:)@Johannes基于模板的解决方案的一个问题是,您无法轻松区分常量类型
      t
      和非常量类型。如果模板的某些函数需要以非常量方式访问向量,则整个模板将无法编译。基于模板的解决方案将从“不可变”数据模板类继承一个“可变”数据模板类,并向其添加可变函数。我不能100%确定是否得到了该类。如果我要存储多个对象,我会使用类型列表或类似的东西。这不应该在编译时设置类型吗?@Johannes是的,这将在编译时设置类型。问题是,如果类型恰好是
      const
      ,并且模板的某些方法需要非const访问,那么这些方法将无法编译。
      #include <vector>
      
      class Data
      {
          std::vector<int> v;
      public:
          Data(std::vector<int>& _v) : v(_v) {}
          Data(const std::vector<int>& _v) : v(_v) {} // error!
      };
      
      class AbstractData {
      public:
          // Common functions use vect() and const_vect()
          void common_function1();
          void common_function2();
      protected:
          virtual vector<int>& vect() const = 0;
          virtual const vector<int>& const_vect() const = 0;
      };
      
      class Data : public AbstractData {
          vector<int>& v;
      public:
          Data(vector<int>& _v) : v(_v) {}
      protected:
          vector<int>& vect() const {
              return v;
          }
          const vector<int>& const_vect() const {
              return v;
          }
      };
      
      class ConstData : public AbstractData {
          const vector<int>& v;
          vector<int> temp;
      public:
          ConstData(const vector<int>& _v) : v(_v) {}
      protected:
          vector<int>& vect() const {
              return temp; // You can choose to throw an exception instead
          }
          const vector<int>& const_vect() const {
              return v;
          }
      };