我正在阅读Herb Sutter的"Exceptional C++"一书,在那本书中我学到了关于pImpl的习语.基本上,我们的想法是为a的private对象创建一个结构class并动态分配它们以减少编译时间(并且还以更好的方式隐藏私有实现).
例如:
class X
{
private:
C c;
D d;
} ;
Run Code Online (Sandbox Code Playgroud)
可以改为:
class X
{
private:
struct XImpl;
XImpl* pImpl;
};
Run Code Online (Sandbox Code Playgroud)
并且,在CPP中,定义:
struct X::XImpl
{
C c;
D d;
};
Run Code Online (Sandbox Code Playgroud)
这看起来很有趣,但我以前从未见过这种方法,既没有在我工作的公司,也没有在我看过源代码的开源项目中.所以,我想知道这种技术真的在实践中使用了吗?
我应该在任何地方使用它,还是谨慎使用?这种技术是否建议用于嵌入式系统(性能非常重要)?
我刚刚注意到一个新术语pimpl成语,这个成语与Bridge设计模式有什么区别?我很困惑.
我也注意到pimpl成语总是用于交换功能,那是什么?有人可以举个例子吗?
我一直认为头文件是一种描述类的"公共接口",在这种情况下,最好将私有字段和函数保存在cpp文件中.
我知道私有字段需要在头文件中,以便其他类可以告诉一个类的实例将消耗多少内存,但是当我要写一个私有帮助函数时,它就出现了,这个函数可以被创建静态,在这种情况下根本不需要它是"类的一部分",它可以很容易地成为类定义的.cpp文件中的常规函数.
然后我想到,通过接受指向类字段的指针/引用而不是期望在类中定义,所有私有函数都可能被重写为静态函数.
这将消除在头文件中声明任何私有函数的需要.
我喜欢遵循约定所以现在我想问一下,它是否被认为是C++中的既定约定,非静态私有函数应该在头文件中?静态函数或静态常量怎么样?
编辑:我将提供一些代码来解释我所得到的:
.h文件:
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass
{
private:
int x;
public:
void combineWithX(int y);
};
#endif
Run Code Online (Sandbox Code Playgroud)
.cpp文件
#include "SomeClass.h"
void someHelper(int* x)
{
*x = (*x) + 1;
}
void SomeClass::combineWithX(int y)
{
someHelper(&x);
x += y;
}
Run Code Online (Sandbox Code Playgroud)
请注意,someHelper(int* x)在cpp文件中引用私有成员x,但不是直接引用,因此不需要出现在标题中.我想知道这种事情是否被认为是"坏风格"
你应该在.h文件中声明类的getters/setter,然后在.cpp中定义它们.或者在.h文件中同时执行它们.你喜欢哪种风格?为什么?我个人喜欢后者,其中所有这些都在.h中,并且只有与.cpp中的setter/getters相关的逻辑相关的方法.
我无法在这个网站上找到类似的问题,但是可以在两个不同的文件上声明一个类.
例如,文件和私有中的所有公共类组件以及不同文件中的其他组件.
publics.h
class test {
public:
int geta();
void seta(int);
};
Run Code Online (Sandbox Code Playgroud)
privates.h
class test {
private:
int a;
};
Run Code Online (Sandbox Code Playgroud)
上面的方法肯定是错的,但有没有这样的方法.
假设我想制作一些应该支持加载图形Image的引擎,所以我有
struct Image;
Image* load_image_from_file(...);
Run Code Online (Sandbox Code Playgroud)
我不希望外部世界知道它到底Image是什么,它们只会指向它.
但是engine我想在内部使用特定类型,例如SDL_Surface在SDL中完全定义的类型.
我可以以某种方式重新映射此文件的图像,以便编译器在SDL_Surface*每次看到时都假定Image*(除了宏)吗?
即我想要的东西 typedef struct SDL_Surface Image;
所有尝试都喜欢
using Image = SDL_Surface;
typedef SDL_Surface Image;
typedef struct SDL_Surface Image;
Run Code Online (Sandbox Code Playgroud)
产生编译时错误(http://codepad.org/1cFn18oh).
我知道我可以使用类似struct Image{SDL_Surface* surface};in engine.c/ engine.cpp但它会创建不必要的间接,我必须输入->surface.另一个肮脏的解决方案是使用显式转换,例如,((SDL_Surface*)image)但我更清楚重命名.
PS.我对C和C++的答案感兴趣.
我有一个导出C++类的MFC扩展DLL,我需要修改类方法的行为.这些更改不会影响类的方法签名.
我不想重新编译使用此库的先前发布版本的"lib"文件的模块.
如果更改修改了函数的入口点地址会发生什么?
例如,构造函数的地址已更改:
Export Ordinal Function Hint Entry Point
[+ ] 3 (0x0003) 2 (0x0002) ??0CLangManager@@QAE@XZ 0x00009CB0 (OLD DLL)
[+ ] 3 (0x0003) 2 (0x0002) ??0CLangManager@@QAE@XZ 0x00009760 (NEW DLL)
Run Code Online (Sandbox Code Playgroud)
我应该重新编译使用该库的模块吗?
我测试了重新编译的库 - 使用新的入口点 - 使用已发布的可执行文件,一切正常.我不确定这种情况是否隐藏了一些副作用.
什么时候需要重新编译链接到DLL的可执行文件?
什么时候二进制兼容性被破坏了?
我似乎无法找到答案,但也许我正在寻找错误的术语.我没有在点击中找到我正在寻找的答案.
我有一堆菜单系统的派生类.
我有一个CControl派生类,它是CEditBox一个CLabel类和一个类的父类.CLabel只不过是将文本附加到SDL_Surface上,然后将其绑定到用于渲染的openGL的纹理. CEditBox将是一个用于显示文本或从用户收集文本的字段,如密码框.显然,CEditBox可以使用标签来处理框内的文本呈现. CControl源于CComponent.
我不能声明CLabel里面,CEditBox除非我包含CLabel在标题中,但我认为我继续得到链接器错误,尽管我的所有标题都包含在#ifndef #define class #endif语法中,但我也是一个菜鸟.相反,我有一个CComponent*指针声明,因为它们是从该类派生的.
精细.现在在CEditBox我的构造函数中:
#include "CLabel.h" //include in .CPP is fine I reckon.
CEditBox::CEditBox() {
CLabel Field; //Create CLabel
InputType = ALL; //Not important for my question related to allowed symbols
Label = &Field; //CComponent pointer to CLabel
}
Run Code Online (Sandbox Code Playgroud)
当这个构造函数返回时,CLabel不会超出范围,因此Feild会被销毁,现在我的指针指向一个未定义的内存块吗?什么是适当的方法来做到这一点?有更好的解决方案吗?
谢谢
我不知道问题已经存在,但有些人认为这是一个更重要的问题.那么现在是实际的代码,你们可以告诉我你是否认为它做错了.基类CMenuObject
#ifndef _CMENUOBJECT_H_
#define _CMENUOBJECT_H_
class CMenuObject { …Run Code Online (Sandbox Code Playgroud) 我正在编写一些针对两个非常相似的硬件版本的软件,直到我使用API来初始化硬件,我才知道我会找回哪种类型.
因为硬件非常相似,我计划有一个父类(TParent),它有一些抽象方法(对于硬件不同的地方),然后是两个子类(TChildA,TChildB),它们以硬件相关的方式实现这些方法.
所以我首先实例化一个TParent的对象检查它是什么样的,然后把它投射到正确的孩子.
但是,当我这样做并调用在子类中完全实现的抽象方法之一时,我得到一个EAbstractError.
例如:
myHardware:=TParent.Create();
if myHardware.TypeA then
myHardware:=TChildA(myHardware)
else
myHardware:=TChildB(myHardware);
myHardware.SomeMehtod();
Run Code Online (Sandbox Code Playgroud)
我假设我不能将父类强制转换为子类,并且还有一种更好的方法可以做到这一点.有什么指针吗?
例如,这是我的代码
QScopedPointer<QTimer> timer2(new QTimer);
Run Code Online (Sandbox Code Playgroud)
但我想定义
QScopedPointer<QTimer> timer2;
Run Code Online (Sandbox Code Playgroud)
在mainwindow.h中创建一个实例
timer2(new QTimer);
Run Code Online (Sandbox Code Playgroud)
在mainwindow.cpp中
怎么样?
c++ ×8
class ×2
oop ×2
pointers ×2
api-design ×1
c ×1
class-design ×1
coding-style ×1
conventions ×1
declaration ×1
delphi ×1
dll ×1
freepascal ×1
inheritance ×1
mfc ×1
pimpl-idiom ×1
qt ×1
scope ×1
standards ×1