2011/04/22
Pointers to class member functions are always interesting
This FAQ show us lot of interesting things.
2010/01/22
Windows Side-by-side Assemblies
From Visual Studio 2005, WinSxS became a mandatory things for Windows application. Especially when you depends on some common DLL components, for example, Common Controls, MS VC CRT, MS GdiPlus. All this need to be specified with the MANIFEST file.
It is a little noisily to generate the MANIFEST manually. So Microsoft do this for you. Indeed, the MANIFEST file was created by `link.exe'. In the C/C++ header file, it is using #pragma instrument to specify the DLL dependency explicitly.
For example MSVCRT: it is specified by 'crtdefs.h' and 'crtassem.h'.
Inside crtdefs.h, it defines the linker comment, like below:
and all the variants, e.g. __LIBRARIES_ASSEMBLY_NAME_PREFIX, __VCASSEMBLY_PUBLICKEYTOKEN, were defined inside `crtassem.h'.
It is a little noisily to generate the MANIFEST manually. So Microsoft do this for you. Indeed, the MANIFEST file was created by `link.exe'. In the C/C++ header file, it is using #pragma instrument to specify the DLL dependency explicitly.
For example MSVCRT: it is specified by 'crtdefs.h' and 'crtassem.h'.
Inside crtdefs.h, it defines the linker comment, like below:
#ifdef _DEBUG
#pragma comment(linker,"/manifestdependency:\"type='win32' " \
"name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT' " \
"version='" _CRT_ASSEMBLY_VERSION "' " \
"processorArchitecture='x86' " \
"publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' " \
"name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \
"version='" _CRT_ASSEMBLY_VERSION "' " \
"processorArchitecture='x86' " \
"publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#endif
and all the variants, e.g. __LIBRARIES_ASSEMBLY_NAME_PREFIX, __VCASSEMBLY_PUBLICKEYTOKEN, were defined inside `crtassem.h'.
2009/03/15
C++ reinterpret_cast
说起 C++ 的类型转换,一共有四种:
- dynamic_cast
- static_cast
- reinterpret_cast
- const_cast
其中 reinterpret_cast 是很有意思的,它可以被看作是 C 语言中强制类型转换的功能,它是一种非检查的暴力转换手段。通过它,我们可以把 指向 int* 转换为 double* 。
当然也可以用来做函数指针的转换,比如:
void FuncA(char *src, int len, int *pLen)
{
*pLen = len;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool (*func_ptr) (char*, int);
func_ptr = reinterpret_cast<bool (*)(char*, int)>(&FuncA);
return 0;
}
当然了也可以用来转换 类成员函数,如:
class ObjectA
{
public:
void FuncA(char *src, int len, int *pLen)
{
*pLen = len;
}
bool FuncB(char *src, int len, int *pLen)
{
*pLen = len;
return false;
}
};
class ObjectB
{
};
int _tmain(int argc, _TCHAR* argv[])
{
bool (ObjectB::*func_ptr) (char*, int);
//ObjectA obj;
func_ptr = reinterpret_cast<bool (ObjectB::*)(char*, int)>(&ObjectA::FuncB);
return 0;
}
但是不能在普通函数和类成员函数之间转换。
2009/01/16
C++ vtable
在 C++ 的OO模型中,很重要的一个特性是运行时多态。运行时多态是通过类的虚方法实现的。看下面这个例子:
C++ 运行时多态, 在执行代码中,主要通过 vtable 实现。让我们用C来重新描述上面的例子。
C的定价物确实有些繁琐,不过基本的结构就是这样了。具体说来是这样:
1,如果一个类 virtual function, 这些 virtual funciton 就会被统一在一个 vtable 中;
2,包含 virtual function 的class 都会有一个指向 vtable structure的指针,如果当前类重写了 virtual function, 在对象初始化的时候相应的虚函数指针就会被替换;
3,虚函数的调用一律通过vtable定位,因为存在vtable这一层中继,就可以保证在运行态可以通过父类的指针执行指向子类对象的方法,因为类对象初始化的时候正确的重写了vtable的内容。
4,一个对象多一个包含virtual function的基类,就会在类变量的结构中多引入一个指向父类vtable structure的指针。在类对象初始化的时候,就需要更多的 vtable 初始化代码。:D
多重继承会导致 vtable 膨胀, Microsoft ATL 引入了一个 ATL_NO_VTABLE __declspec(novtable) C++ 扩展。关于这个,下回再说~~~
其实这个例子里面还有一个小问题, 不知道大家能不能看出来啊!
struct IObject {
virtual void MethodA() = 0;
virtual int MethodB(char *) = 0;
};
class A : public IObject {
public:
virtual void MethodA() {
std::cout << "method A" << std::endl;
};
virtual int MethodB(char *p) {
std::cout << "method B " << p << std::endl;
return 0;
};
public:
int MethodC(int c) {
std::cout << "method C non-virtual" << std::endl;
return ++c;
}
private:
int mem_;
};
int main(int argc, cahr *argv[])
{
IObject *pObj = new A;
pObj->MethodA();
pObj->MethodB(NULL);
// FIXME: This is a compile error!
pObj->MethodC(1); // error
delete A;
return 0;
};
C++ 运行时多态, 在执行代码中,主要通过 vtable 实现。让我们用C来重新描述上面的例子。
// VTABLE of class IObject
struct I_IObject {
void *pMethodA(void);
int *pMethodB(char *);
};
// Instance variant type of IObject
struct IObject {
struct I_IObject *vtable_this;
};
// VTABLE of class A
struct A;
struct I_A {
void *pDtor(A*)
};
// Instance object variant type of class A
struct A {
struct I_IObject *vtable_IObject;
struct I_A *vtable_this;
int *pMethodC(int);
int mem_;
};
void A_MethodA (void) {
printf("method A\n");
}
int A_MethodB (char *p) {
printf("method B %s\n", p);
}
int A_MethodC (int c) {
printf("method C non-virtual\n");
return ++c;
}
void A_dtor(struct A *_this) {
free(_this);
}
struct A *A_ctor() {
struct A *p = malloc(sizeof(struct A));
// Non-virtual function will be assign the value directly.
p.pMethodC = &A_MethodC;
/////////////////////////////////////////////////
// vtable initialization code
#ifdef A_MethodA
p.vtable_IObject->pMethodA = &A_MethodA;
#else
p.vtable_IObject->pMethodA = &IObject_MethodA; // Warning!
#endif
#ifdef A_MethodB
p.vtable_IObject->pMethodB = &A_MethodB;
#else
p.vtable_IObject->pMethodB = &IObject_MethodB; // Warning!
#endif
// vtable of A itself
p.vtable_self->pDtor = &A_dtor;
return p;
}
int main(int argc, char *argv[])
{
IObject *pObj = (IObject*) A_ctor();
pObj->vtable_self->pMethodA();
pObj->vtable_self->pMethodB(NULL);
A_dtor(pObj);
return 0;
}
C的定价物确实有些繁琐,不过基本的结构就是这样了。具体说来是这样:
1,如果一个类 virtual function, 这些 virtual funciton 就会被统一在一个 vtable 中;
2,包含 virtual function 的class 都会有一个指向 vtable structure的指针,如果当前类重写了 virtual function, 在对象初始化的时候相应的虚函数指针就会被替换;
3,虚函数的调用一律通过vtable定位,因为存在vtable这一层中继,就可以保证在运行态可以通过父类的指针执行指向子类对象的方法,因为类对象初始化的时候正确的重写了vtable的内容。
4,一个对象多一个包含virtual function的基类,就会在类变量的结构中多引入一个指向父类vtable structure的指针。在类对象初始化的时候,就需要更多的 vtable 初始化代码。:D
多重继承会导致 vtable 膨胀, Microsoft ATL 引入了一个 ATL_NO_VTABLE __declspec(novtable) C++ 扩展。关于这个,下回再说~~~
其实这个例子里面还有一个小问题, 不知道大家能不能看出来啊!
2006/12/25
最简化的Nmake Makefile
!include <win32.mak>
## Link with MSVCRT and MSVCP
#.cpp.exe:
# cl -nologo -MD -W3 -O1y -EHsc -I. $**
.cpp.exe:
cl -nologo -W3 -O1y -EHsc -I. $**
clean:
del /q /f *.exe *.obj
最简化的GNUMakefile
## GNU Makefile with MinGW/MSYS
## MinGW 下面简化的Makefile 需要 MSYS
## It can be invoked like `mingw32-make hello.exe`
## This will compile the hello.cpp to hello.exe
CXXFLAGS=-I. -O3
## 没有下面这条指令, 后缀通配指令不能识别 .cpp.exe
.SUFFIXES: .exe
.cpp.exe:
g++ -Wall $(CXXFLAGS) -o $@ $<
.PHONY : clean
clean:
rm -f *.exe *.obj *.o
订阅:
博文 (Atom)
BlockChain 相关电子书
@copyright of Sam Chadwick - https://thehub.thomsonreuters.com/groups/bitcoin/blog/2017/09/10/blockchain-paper Blockchain Papers A c...
-
为Windows 10 添加 拼音加加双拼 输入方案 把下面的内容保存为 ppp.reg, 然后双击导入注册表,Pinyin PlusPlus双拼输入方案就有了。 Windows Registry Editor Version 5.00 [HKEY_CURRENT...
-
算起来到这里已经一年多了, 中间断断续续当然了也包括一些可观的原因,一共也没有放多少东西上来。 总算还有两片篇幅较长的原创,也算是聊以自慰了。 再接再厉好了!希望自己能够百尺竿头更进一步~~~
-
Today I do update the JavaScript syntax script for VIM to 0.7.2. Until now PRC 2007.01.30-21:37 my script got: Rating 332/99, Downloaded by ...