今天早上我正在阅读每本程序员应该拥有的The Pragmatic Programmer第3章“基本工具”这本书,他们提到了代码生成工具。 他们提到了一个用于C ++程序的Perl脚本,它帮助自动化为私有数据成员实现get / set()成员函数的过程。
有没有人知道这样的脚本以及在哪里找到它?我一直无法找到合适的谷歌关键字来找到它。
答案 0 :(得分:9)
虽然它没有直接回答您的问题,但您可能会发现生成的代码对于管理C ++中的属性实际上是不必要的。以下模板代码将允许您方便地声明和使用属性:
// Declare your class containing a few properties
class my_class {
public:
property<int> x;
property<string> y;
...
};
...
my_class obj;
cout << obj.x(); // Get
obj.y("Hello, world!"); // Set
以下是代码:
// Utility template to choose the 2nd type if the 1st is void
template <typename T, typename U>
struct replace_void {
typedef T type;
};
template <typename T>
struct replace_void<void, T> {
typedef T type;
};
// Getter/setter template
template <typename T, typename D = void>
class property {
typedef typename replace_void<D, property>::type derived_type;
derived_type& derived() { return static_cast<derived_type&>(*this); }
public:
property() {} // May be safer to omit the default ctor
explicit property(T const& v) : _v(v) {}
property(property const& p) : _v(p._v) {}
property& operator=(property const& p) { _v = p._v; return *this; }
T operator()() const { return _v; } // Getter
void operator()(T const& v) { derived().check(v); _v = v; } // Setter
protected:
// Default no-op check (derive to override)
void check(T const& v) const { (void)v; //avoid unused variable warning}
private:
T _v;
};
check()
是一个测试被赋值是否有效的函数。您可以在子类中覆盖它:
class nonnegative_int : public property<int, nonnegative_int> {
public:
// Have to redeclare all relevant ctors unfortunately :(
nonnegative_int(int v) : property<int, nonnegative_int>(v) {}
void check(int const& v) const {
if (v < 0) {
throw "Yikes! A negative integer!";
}
}
};
你有它 - 外部生成的getter / setter函数的所有优点,没有任何混乱! :)
您可以选择让check()
返回表示有效性的bool
,而不是抛出异常。您原则上可以添加一个类似的方法access()
,用于捕获对该属性的读取引用。
编辑:正如Fooz先生在评论中指出的那样,类作者可以在不修改类的逻辑结构的情况下更改实现(例如,将property<int> x
成员替换为一对x()
方法),虽然二进制兼容性丢失,因此用户需要在进行此类更改时重新编译其客户端代码。 这种无痛地融入未来变化的能力实际上是人们首先使用getter / setter函数而不是公共成员的主要原因。
效果说明:因为我们使用CRTP来实现“编译时多态”,所以没有虚拟调用开销来提供自己的check()
子类,您无需声明它virtual
。
答案 1 :(得分:3)
由于大多数C ++私有成员不应该通过Get / Set样式函数访问,这似乎是一个坏主意。
有关其原因的简单示例,请考虑C ++ std :: string类。它的私人成员可能看起来像这样(确切的实现并不重要):
private:
int last, len;
char * data;
你认为为那些提供获取/设置成员是否有意义?
答案 2 :(得分:2)
我无法帮助您了解该特定脚本的位置。但是,有quite a lot代码生成工具。您甚至可能已经将所需内容作为IDE的一部分。有关如何,为何以及是否使用代码生成工具的更多辩论/意见,您可以查看this stackoverflow question。我喜欢这个问题的接受答案。
答案 3 :(得分:2)
我知道有一位程序员uses Perl to augment the C preprocessor涉及到宏(latest version of that project)。基本的想法是你会决定一些约定来告诉你的Perl脚本何时生成一个getter或setter:
struct My_struct {
//set
//get
int x;
int y;
//get
int z;
};
考虑到这样的代码,我可以编写一个脚本来查找在成员变量声明之前在行上的注释“get”或“set”组成的注释行,然后用简单的setter / getters替换它们。在上面的例子中,我将在关联的成员变量定义之后生成void set_x(int i),int get_x()和int get_z()。
警告:不要使用s ///就地执行此操作。相反,单独扫描每一行,如果你找到一个合适的注释行,将“我需要一个getter / setter”的东西推到一个堆栈上,那么当你看到相关的成员变量时,弹出堆栈并生成代码
细节中有一些恶魔,但总的来说就是这个想法。
答案 4 :(得分:2)
您希望脚本不加选择地为所有私有成员生成get / set函数吗?那不是一个非常有用的剧本;你可能不会在谷歌找到它。如果您希望能够以某种方式标记您的成员变量并为您自动生成getter和/或setter骨架,那么IDE宏似乎更合适。试试谷歌。