【问题标题】:C++ const correctness / missing const constructor for class supporting both const and non-const instances支持 const 和非 const 实例的类的 C++ const 正确性/缺少 const 构造函数
【发布时间】:2020-01-17 20:26:40
【问题描述】:

我有几个链接类,如下例所示,我希望它们同时支持非常量和常量实例(如函数x):

#include <vector>

class Original;

class View
{
public:
    View(Original *that) : m(that) {}
    Original * m;
};

class Original
{
public:
    auto columns() {return View(this);}
    //~ const auto columns() const {return View(this);} // comment #1
    std::vector<int> m;
};

void x()
{
    Original o1;
    const Original o2;
    //~ o2.columns(); // comment #2
}

我用g++ -std=gnu++17 -c const.cpp编译得到如下结果:

案例 1:同上:编译得很好(这让我很困惑,因为在下面的案例 2 中我只是添加了一个调用,它会失败......)

案例 2:取消注释 #2,我们得到...

const.cpp: In function 'void x()':
const.cpp:24:13: error: passing 'const Original' as 'this' argument discards qualifiers [-fpermissive]
  o2.columns(); // comment #2
             ^
const.cpp:15:7: note:   in call to 'auto Original::columns()'
  auto columns() {return View(this);}
       ^~~~~~~

案例 3:此外,取消注释 #1;这会产生......

const.cpp: In member function 'const auto Original::columns() const':
const.cpp:16:46: error: invalid conversion from 'const Original*' to 'Original*' [-fpermissive]
  const auto columns() const {return View(this);} // comment #1
                                              ^
const.cpp:8:2: note:   initializing argument 1 of 'View::View(Original*)'
  View(Original *that) : m(that) {}
  ^~~~

在我看来,我需要一个构造函数来创建一个 const 对象,而这在 C++ 中是不可用的。 所以我尝试将View 设为模板类,以同时支持常量和非常量成员m。但我并没有马上让它运行起来,反正感觉很丑。

任何人有任何提示?已经非常感谢了!

【问题讨论】:

  • 案例 2 和案例 3 是截然不同的错误,当他们一次只关注一个错误时,问题往往对其他人更有用。你有没有比这两个问题都来自同一个程序这一事实更好的理由来组合这些问题?
  • 不应该没有前导~以防未注释
  • @JaMiT:我只是想提示一下我已经尝试过的内容;错误相互依赖
  • @wolfgang 是什么让您认为这些错误相互依赖?他们不是。如果您取消注释 #1 而不是 #2,会发生什么?您仍然会收到“案例 3”错误!这强烈暗示了独立性。
  • 抱歉,我刚刚意识到最初的问题错过了我希望类同时支持 const 和非const 用法的关键部分,例如在函数x 中。我现在更新了问题...

标签: c++ constructor constants


【解决方案1】:

您的View 构造函数采用Original 指针,但您试图将指针传递给const Original!您需要构造函数(和成员变量)来反映这一点:

class View
{
public:
    View(const Original *that) : m(that) {}
    const Original * m;
};

在这里运行:https://ideone.com/nEgFxD

但是,如果您可以接受制作深层副本的打击,那么最好完全避免指针业务:

//Declare Original out so View can use its copy/move constructor
class Original
{
public:
    auto columns();
    const auto columns() const;
    std::vector<int> m;
};

//Full declaration/implementation of View
class View
{
public:
    View(const Original &that) : m(that) { }
    Original m;
};

//Now that View's constructors are defined, implement these Original funcs
auto Original::columns() {return View(*this);}
const auto Original::columns() const {return View(*this);} // comment #1

int main()
{
    Original o1;
    const Original o2;
    o2.columns(); // comment #2
}

在这里运行:https://ideone.com/HnpQ38

【讨论】:

  • 对于您的第一个建议,我可能过于简化了我的示例,因为我还需要m 不是 const 的情况。对于您的第二个 - 看起来不错,但 Original.m 的副本不是很贵吗?
  • 啊,那我建议制作一个深拷贝而不是浅拷贝@wolf。你想让我用一个例子来更新我的答案吗?
  • @wolf 关于第二个例子,是的,它会有点贵,但如果你必须有一个非常量 Original,你唯一的方法是(合法地)从一个 const @ 得到它987654331@将要复制。
  • 如果其他一切都失败了,为 const 和非 const m 提供模板 View 应该可以不用复制
  • 它应该......但是如果你要进行相同的调用,无论你有一个 const 指针还是非常量指针,为什么不能一切都只是 const 呢? @狼
【解决方案2】:

这是我今天想出来的,但基于模板(我认为这很丑陋);它同时支持 const 和非 const 用法(如函数 x):

#include <vector>

class Original;

template<class T>
class View
{
public:
    View(T *that) : m(that) {}
    T * m;
};

class Original
{
public:
    auto columns() {return View(this);}
    const auto columns() const {return View(this);}
    std::vector<int> m;
};

void x()
{
    Original o1;
    const Original o2;
    o2.columns();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多