C++ 如何在使用pimpl习惯用法时创建私有静态常量字符串 背景
我一直在学习如何使用Herb Sutter在本页描述的更新的c++11方法实现pimpl习惯用法: 我试图通过向私有实现添加一个成员变量来修改这个示例,特别是std::string(尽管char*也有同样的问题) 问题 由于使用静态常量非整数类型,这似乎是不可能的。只能对整型进行类内初始化,但由于整型是静态的,因此也无法在构造函数中进行初始化 此问题的解决方案是在头文件中声明私有变量,并在实现中对其进行初始化,如下所示: 但是,这个解决方案不适合我,因为它破坏了我试图通过pimpl习惯用法实现的封装 问题: 使用pimpl习惯用法时,如何在隐藏的内部类中隐藏非整数静态常量变量 例子 下面是我能想出的最简单(不正确)的例子来演示这个问题: Widget.h:C++ 如何在使用pimpl习惯用法时创建私有静态常量字符串 背景,c++,c++11,pimpl-idiom,C++,C++11,Pimpl Idiom,我一直在学习如何使用Herb Sutter在本页描述的更新的c++11方法实现pimpl习惯用法: 我试图通过向私有实现添加一个成员变量来修改这个示例,特别是std::string(尽管char*也有同样的问题) 问题 由于使用静态常量非整数类型,这似乎是不可能的。只能对整型进行类内初始化,但由于整型是静态的,因此也无法在构造函数中进行初始化 此问题的解决方案是在头文件中声明私有变量,并在实现中对其进行初始化,如下所示: 但是,这个解决方案不适合我,因为它破坏了我试图通过pimpl习惯用法实现
#ifndef WIDGET_H_
#define WIDGET_H_
#include <memory>
class Widget {
public:
Widget();
~Widget();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif
请注意,此示例未能编译,因为变量TEST不是整型,所以无法在声明时赋值;但是,因为它是静态的,所以这是必需的。这似乎意味着这是不可能做到的
我整个下午都在搜索之前的问题/答案,但找不到任何能提出保留pimpl惯用语信息隐藏特性的解决方案
解决方案观察:
在上面的示例中,我试图在Impl类声明中分配TEST的值,该声明位于Widget.cpp内部,而不是它自己的头文件。Impl的定义也包含在Widget.cpp中,我相信这是我困惑的根源
通过简单地将测试的分配移到Impl声明之外(但仍然在Widget/Impl定义中),问题似乎得到了解决
在下面的两个示例解决方案中,可以使用
pimpl->TEST
尝试将不同的字符串分配到测试中,即
pimpl->TEST=“changed”
导致编译器错误(应该如此)。此外,尝试从小部件外部访问pimpl->TEST也会导致编译器错误,因为pimpl被声明为小部件的私有
所以现在TEST是一个常量字符串,它只能被一个小部件访问,在public头中没有命名,并且一个副本在小部件的所有实例之间共享,完全按照需要
解决方案示例(char*):
在使用char*的情况下,注意添加了另一个const关键字;这对于防止将测试更改为指向另一个字符串文字是必要的
Widget.cpp:
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST = "test";
Impl() { };
~Impl() { };
};
Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }
#include "Widget.h"
#include <stdio.h>
class Widget::Impl {
public:
static const char *const TEST;
Impl() { };
~Impl() { };
};
const char *const (Widget::Impl::TEST) = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST;
Impl() { };
~Impl() { };
};
const std::string Widget::Impl::TEST = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
#包括“Widget.h”
#包括
类小部件::Impl{
公众:
静态常量字符*常量测试;
Impl(){};
~Impl(){};
};
常量字符*常量(小部件::Impl::TEST)=“TEST”;
Widget::Widget():pimpl(新Widget::Impl()){}
小部件::~Widget(){}
解决方案示例(字符串):
Widget.cpp:
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST = "test";
Impl() { };
~Impl() { };
};
Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }
#include "Widget.h"
#include <stdio.h>
class Widget::Impl {
public:
static const char *const TEST;
Impl() { };
~Impl() { };
};
const char *const (Widget::Impl::TEST) = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST;
Impl() { };
~Impl() { };
};
const std::string Widget::Impl::TEST = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
#包括“Widget.h”
#包括
类小部件::Impl{
公众:
静态常量std::字符串测试;
Impl(){};
~Impl(){};
};
const std::string小部件::Impl::TEST=“TEST”;
Widget::Widget():pimpl(新Widget::Impl()){}
小部件::~Widget(){}
更新:
<>我意识到这个问题的解决方案完全不与piml习惯用法无关,只是定义静态常量的标准C++方式。我已经习惯了其他语言,如java,在声明的时候必须定义常量,所以我的C++经验不足,使我无法实现这一点。我希望这可以避免对这两个主题的混淆。\include
#include <memory>
class Widget {
public:
Widget();
~Widget();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
/*** cpp ***/
#include <string>
class Widget::Impl {
public:
static const std::string TEST;
Impl() { };
~Impl() { };
};
const std::string Widget::Impl::TEST = "test";
Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }
类小部件{
公众:
Widget();
~Widget();
私人:
类Impl;
std::唯一的ptr pimpl;
};
/***cpp***/
#包括
类小部件::Impl{
公众:
静态常量std::字符串测试;
Impl(){};
~Impl(){};
};
const std::string小部件::Impl::TEST=“TEST”;
Widget::Widget():pimpl(新Impl()){}
小部件::~Widget(){}
您可能想考虑制作<代码>测试> /Cord>一个静态函数,它返回<代码> const STD::String和。这将允许您以内联方式定义它。
您也可以在示例中用constexpr
替换const
,它将编译
class Widget::Impl {
public:
static constexpr std::string TEST = "test"; // constexpr here
Impl() { };
~Impl() { };
};
更新:
看来我错了。。。当我需要常量时,我总是存储原始字符串
class Widget::Impl {
public:
static constexpr char * const TEST = "test";
};
根据使用模式,它可能是合适的,也可能不是。如果没有,请按照另一个答案中的解释定义变量。错误:constexpr变量不能具有非文字类型“const std::string”。这种方法的std::string版本给了我一个关于非文字类型的类似错误。char *方法也不起作用,错误<代码> ISO C++禁止将字符串常量转换为“char *”/COD> >我编写的代码没有错误,所以我不知道你在说什么。在我的代码中没有从
std::string
到char*
的转换。从C语言中构造一个C++字符串是很容易的。编译器错误指向第一个双引号包围“test”,所以它似乎在讨论将字符串赋给char *变量。这个解决方案似乎起作用,但是在编写了一些测试代码尝试之后,在实践中使用起来感觉非常尴尬。而且还需要对每个私有字符串进行函数调用,这表明它不能很好地扩展。这被认为是解决问题的“最佳实践”方法吗?你必须弄清楚你想要什么。如果在pimpl
对象中声明字符串,可能是因为您不需要对它们进行公共访问。否则,你会在主类中声明它们。@richard hodges:很抱歉,我误读了你最初的回答,我以前的回答