re: 一个有趣的小问题 OwnWaterloo 2009-09-01 21:37
@莫失莫忘
静态成员本来就可以通过
1. 类名
S::sum
2. 实例
S s;
s.sum;
两种形式访问, 毫无区别, 推荐第1种形式。
this->sum 依然是 S::sum, 而不会是s的非静态成员。
它根本就没有非静态的sum, 难道编译器还因为this->sum专门给它再加这么一个非静态sum么?
re: 一个有趣的小问题 OwnWaterloo 2009-09-01 21:31
@莫失莫忘
你是从那句解释中看出有解引用一说的?
re: VC6中的简易delegate实现 OwnWaterloo 2009-09-01 20:54
@李现民
如果楼主打算试试boost.function on vc6, 请告知下结果哦~~~
我对vc6吐出的错误有些恐惧~~~
re: VC6中的简易delegate实现 OwnWaterloo 2009-09-01 20:50
@李现民
boost.function有3种使用语法:
1.
function<void ()> ...
function<void (int) > ...
function<int (std::string,int) > ...
2.
function<void> ...
function<void,int> ...
function<int ,std::string,int > ...
3.
function0<void> ...
function1<void,int> ...
function2<int ,std::string,int > ...
越往后, 语法越丑陋, 但受更多编译器支持。
可以试试在vc6上是否支持boost.function的2使用方法(第1种就不要指望了~~~)
如果行, 就看boost是怎么做的。
我估计后一种语法的实现依然要偏特化, 所以不行。
那就只能使用最丑陋的第3种语法了。
re: 低耦合模块间的通信组件:两个模板 OwnWaterloo 2009-08-23 15:50
@Kevin Lynx
我说说我的看法啊, 你看看是否合理。
将:
void OnE1(tuple<e11,...> );
void OnE2(tuple<e21,...> );
void OnE3(tuple<e31,...> );
转化为:
OnEvent(int e, any );
是合理的,因为这样做可以很好的适应"增加event种类"这一变化。
对"需要增加很多event"或者"event暂时未知"的情况, 是很有用的。
也算是降低了耦合度吧, 因为
>逻辑层也不需要改,只改UI的通知处理即可。
嗯……
相比一些其他的很严格的抽象方式, 比如将每个OnE1设置为纯虚…… 那简直是自讨苦吃……
一旦增加一个OnEx的纯虚, ui代码就需要改。
如果不是纯虚, 或者使用OnEvent(int e, any );就有一个"缓合"的机会, 可以慢慢来~~~
但是, 我有一个猜测, 你看看对不对:
OnEvent(int e, any );
添加这一层, 总工作量不会有丝毫减少, 甚至会增加。
有可能ui端会:
switch (e)
如果e的种类继续增加, 还可能在ui端继续转变为:
ReplyE1(tuple<E11, ... > );
ReplyE2(tuple<E21, ... > );
ReplyE3(tuple<E31, ... > );
再次申明啊, 我觉得OnEvent(int e, any );是有好处的。
logic和ui通过这个通信。
logic内部是否NotifyE1,NotifyE2的形式? UI是否采用RE1,RE2的形式?
这个是完全解耦了。
只是数据格式始终解不了。
>看过一些人直接在MFC的OnXXX里写一堆逻辑代码就觉得受不了。
嗯…… 我曾经就写过让你受不了的代码~~~
当然, 现在我也受不了那代码了……
但是呢, 现在又没机会去做这种logic,ui分离的事, 只是猜测OnEvent(int e, any );会使得总代码量增加。
希望能得到你的经验之谈~~~
re: 低耦合模块间的通信组件:两个模板 OwnWaterloo 2009-08-23 14:58
光顾着说笑了…… 说点正事。
这样做算不上"降低耦合"吧?
void OnE1(tuple<e11,...> );
void OnE2(tuple<e21,...> );
void OnE3(tuple<e31,...> );
和:
void OnEvent(int e, any );
的耦合性不是完全一样么?
log和UI依然必须"协商"每个事件的参数是怎样的。
只是后一种方式, 将通信的接口纳入一个之中, 而不是每产生一个新事件就添加一个, 也就是说, 这个接口可以完全固定下来了, 不会再发生变化。
re: 低耦合模块间的通信组件:两个模板 OwnWaterloo 2009-08-23 13:53
@Kevin Lynx
嗯,boost确实有点重……
那么我们抛弃boost::tuple, 使用std::tr1::tuple吧~~~
不过any…… 这可怜的家伙没被采纳…… 得自己实现……
re: 低耦合模块间的通信组件:两个模板 OwnWaterloo 2009-08-23 13:35
嘿嘿嘿嘿~~~
设计来、设计去,回到了经典的WndProc模式:
typedef HRESULT (CALLBACK* WndProc)(HWND,UINT,WPARAM,LPARAM);
因为现在有模板这个高级货, 所以HWND,WPARAM,LPARAM可以塞到一起,变成:
typedef R (*OnNotify)(long type, xxx data);
然后呢, 为了更方便的将各种东西塞入data, lz创造了一个 Param.
试试boost.tuple?
为了让一个签名接受不同类型的tuple/Param, 再将它们塞入一个any/void*。
旧瓶新酒~~~
re: 低耦合模块间的通信组件:两个模板 OwnWaterloo 2009-08-23 13:27
@megax
同意。 一旦any_cast出错,就是一个不能逃避,必须得修改掉的错误。
相对于void*, any能起到的作用只是开发时的debug?
发布时再改回无检查的void* ? 还要注意释放的问题……
re: 一个有趣的小问题 OwnWaterloo 2009-08-20 23:21
@胡友蒙
代码中只出现了无效地址, 但并没有解引用。
>而且很多时候都是致命的
这样做至少在i386上是100%不会出现任何问题, 所以, 不用说得这么吓人。
re: 一个有趣的小问题 OwnWaterloo 2009-08-20 22:34
(S)(*(sa+100*sizeof(S))).a();
这个表达式有2个小问题, 其他都到位。
由此, 可以给他解释另一个更经典的……
static_cast<S*>(0)->a();
-_-; ...
template<typename T>
class Obj;
template<typename T>
class Obj_iteator { ... };
template<typename T>
class Obj { ... };
这样吗?
re: 强大的bcb OwnWaterloo 2009-08-15 12:50
2和4都是符合标准的, 引用只能绑定到左值, 只有const引用才可以绑定到临时对象。
FileLoader::RawData FileLoader::GetRawData() const;
const FileLoader::RawData& r = loader.GetRawData();
// 估计不是所希望的, 应该这样才对:
const FileLoader::RawData v = loader.GetRawData();
void func( Obj &a )
func( Obj() ); // error in ISO C++
void func(const Obj& a);
func( Obj() ); // ok
1. 我只记函数模板中, 局部类可以使用模板参数。
反过来, 还真不记得了……
连同3, 这种使用了生僻模板技术的代码, 编写的时候就应该注意按标与各编译器的支持程度的差异。
@11
> 但是就这个应用来说根本用不到很大的精度
扯谈!
那可不可以说“就这个应用根本不需要考虑效率”?
使用多线程(线程池都免了)的效率完全足够, 并且——我一直强调的——它编码简单, 充分利用"OS已经实现的调度机制",而不是自己重复去发明一套弱小的调度功能。
一上来就抛出一句“典型滥用xxx”, 提出一个所谓的解决方案。
典型的“什么事都想靠自己解决”的初级程序员作法。
@11
@11
>Sleep(10); //10毫秒,可以根据需要的精度调整此检查频率
嘿嘿, 是不是我需要更高精度的时候, 应该Sleep(5); ???
你看看这个:
999...999 a_long_delay_work.exe
还觉得你那个方法“效率高”?
你想想"可以根据需要的精度调整此检查频率"这句话, 当需要的精度要求达到极限时, 比如Sleep(0); 那个while是不是一个"忙等"?
你以为Sleep没有开销吗? 还Sleep(10)呢, 哈哈哈。
你的代码简单吗? 全都是伪代码。
而且我也说了, OS调度里面, 这些代码都有, 你老人家何苦要去和它争呢?
就这Sleep(10) , 还争什么呢争……
你这方案, 至少得算出到下一个任务开始前, 应该大致Sleep多久, 它才不算一个忙等。
-------- --------
而且, 这方案还必须是“先得到所有任务”, 再跑这个半死循环, 才可以。
如果需要再跑半死循环的中途, 新建定时任务呢?
这需求很常见, 很多类似“记事簿”的软件都要提供这功能, 而且是随时插入新的任务。
显然, 你必须至少要开2个线程了, 1个用于用户输入, 1个用来跑半死循环。
“任务队列”现在被2线程共享, 又需要加锁来同步。
这就是我说的, 自己调度会造成编码复杂的原因, 懂?
别人的方案有何优势与劣势?
如此多的方案,它们各自何种情况下是最佳方式?
想过没? 同学?
不要想都不想——如果Sleep(10)就是你想的结果, 那我真没什么必要和你继续说下去了……——就随便扣个帽子, 你以为能显示出你很能吗?
@Stupid ET
这些代码是你高中写的?? 牛……
我觉得这思路挺好, 将n个任务分到不同线程, 然后用Sleep的方式通知OS。
谁知道OS里面会不会有:
“来一个排序, 以一个小的粒度检查时间来运行要运行的”线程
这种调度算法呢?
谁知道OS会不会比ls某位的算法更差呢?
谁知道windows下的创建线程开销会比ls某位的算法高呢?
这些都不知道, 要测也不方便。
但是, 编码简单很多~~~ 同时线程间的同步也很方便处理。
KISS~~~
@OwnWaterloo
哦, 原来是个backward compatibility函数……
> Sleep(InputHandle()+2000); // 主线程暂停等待其他线程运行完毕
严格给的说, 要用 WaitForMultipleObjects。
如果人品非常差, 延迟2秒还是有主线程先结束的可能, 因为调度顺序是未知的。
> 因为调度未知
从CreateThread开始, 到次线程Sleep 之间会有未知时间的间隔。
所以, 传给次线程的, 不应该是delay, 而是awake_time。
次线程在Sleep前一刻, 根据awake_time和current_time, 计算Sleep多久。
这样, 精度就不受CreateThread,到Sleep之间那段未知时间的影响。
如果精度还要提高, 可以用WaitableTimer。
> CreateThread
在vc上用_beginthreadex代替。 dev c++如果是用的mingw, 也有这个函数。
最后一点………… 其实偷懒的话去查AT的用法 ……
run -> cmd -> at /?
直接写个bat文件:
at xxxx notepad
at yyyy calc
....
而不用写一个配置文件, 然后用一个程序去读, 再执行……
功能差不多, 精度可能低一些。
re: FOX TOOLKIT 学习 - 文本显示 OwnWaterloo 2009-06-27 11:46
@visualfc
原来是要处理utf8...
我指的是
c89 stdlib.h
mbstowcs
wcstombs
c99 wchar.h
mbsrtowcs
wcsrtombs
转换跟locale有关, 标准只保证有"C"和""两种locale存在。
其他的也是跟实现相关。这样的话,上面4个函数的可移植优势就不大了。
同时msvc的crt还不支持utf8 ...
那就用iconv吧。。。 挺好的一个库。
为什么一定要找基于fox的方案呢?
另外,FXString 存放的总是utf8?
要将其显示在控件上?
将 utf8 转为 utf16 再用 xxxxW 函数应该就可以显示了。
应该不用转成 gbk 然后用 xxxxA 函数。
re: FOX TOOLKIT 学习 - 文本显示 OwnWaterloo 2009-06-25 10:54
>>在Windows平台上我使用了MultiByteToWideChar来实现代码页转换,如果谁能有基于FOX的解决方案,欢迎进行指点和帮助。
有基于C标准库的方案。
re: 查看源文件预处理结果 OwnWaterloo 2009-06-08 15:27
@zhichyu
应该跟源文件行号有关, 具体我不清楚
re: 技术回归01-Windows内存分配工具 OwnWaterloo 2009-06-04 12:04
@万连文
微软的哪? MFC?
上面的命令行 cl /MD 已经告诉编译器链接到动态库了。
vc6不支持是因为它只有静态库。 crt的动态库是跟.net那一套东西一起出来的。
re: 技术回归01-Windows内存分配工具 OwnWaterloo 2009-06-04 10:32
sorry…… 不小心提交了2次 ……
我自己删掉一个 ……
re: 技术回归01-Windows内存分配工具 OwnWaterloo 2009-06-04 10:32
1#include <stddef.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <vector>
5
6#include <stdexcept>
7
8
9#if defined(_MSC_VER) && _MSC_VER<1400
10#include <new.h>
11namespace std { using ::set_new_handler; using ::new_handler; }
12#else
13#include <new>
14#endif
15
16
17void* allocate(size_t size) {
18 if (size==0) size = 1;
19 for (void* p=0;;) {
20 p = malloc(size);
21 if (p) {
22 printf("allocate %p\n",p);
23 return p;
24 }
25 std::new_handler handler = std::set_new_handler(0);
26 std::set_new_handler(handler);
27 if (handler)
28 handler();
29 else
30 throw std::bad_alloc();
31 }
32}
33
34void deallocate(void* ptr) {
35 printf("deallocate %p\n",ptr);
36 free(ptr);
37}
38
39void* operator new(size_t size) { return allocate(size); }
40void* operator new[](size_t size) { return allocate(size); }
41void operator delete(void* ptr) { deallocate(ptr); }
42
43class C {
44 static int count;
45public:
46 static bool fail;
47 C() {
48 if (fail)
49 throw std::exception();
50 printf("C::C(),%d\n",++count);
51 }
52 ~C() {
53 printf("C::~C(),%d\n",count--);
54 }
55 C(const C& ) {
56 printf("C::(const C&),%d\n",++count);
57 }
58
59
60 //void* operator new(size_t,void* place) { return place; }
61 void* operator new(size_t size) { return allocate(size); }
62 void* operator new[](size_t size) { return allocate(size); }
63 void operator delete(void* ptr) { deallocate(ptr); }
64};
65bool C::fail;
66int C::count;
67
68struct S {
69 static bool fail;
70 S() {
71 if (fail)
72 throw std::exception();
73 printf("construct\n");
74 }
75 ~S() {
76 printf("destroy\n");
77 }
78};
79bool S::fail;
80
81void test_class(int dim) {
82 if (dim<=0)
83 return;
84 C::fail = dim==4;
85 C* arr = new C[dim];
86 delete[] arr;
87}
88
89
90void test_global(int dim) {
91 if (dim<=0)
92 return;
93 S::fail = dim==4;
94 S* arr = new S[dim];
95 delete[] arr;
96}
97
98int main() {
99 using namespace std;
100 int dim = 0;
101 for (printf("input dim: ");scanf("%d",&dim)==1;printf("input dim: "))
102 {
103 try {
104 test_class(dim);
105 }
106 catch (std::exception& ) {
107 printf(" ---- catch an exception ----\n");
108 }
109 try {
110 test_global(dim);
111 }
112 catch (std::exception& ) {
113 printf(" ---- catch an exception ----\n");
114 }
115 }
116}
117
有两个底层分配函数allocate和deallocate,它们使用malloc和free。
用这两个函数实现全局的3个op new,op new[], op delete,没有op delete[]
还用这两个函数实现了C的3个op new,op new[], op delete,同样没有op delete[]
用如下参数编译
cl /EHsc /MD /analyze /W3
你看看结果吧。
我用vc8、9测过(vc6不支持动态crt库,vc10我没装)。
反正两处delete[] arr;都没有调用 op delete。
它们调用那个全局的,没有被重写的op delete[]。
如果静态链接,该全局默认的op delete[]会被inline, 再调用该编译单元中定义的op delete。
如果动态链接,op delete[]不会被inline,会调用crt库中提供的op delete。
总之,这两处delete[] arr;都没有调用deallocate。
当然, 你可以说你只静态链接到crt库。
也可以说你的allocate和deallocate底层实现绝对会一直保持与vc提供的crt兼容。
但是,你的代码的用户了解么?
难道你打算在文档中写“使用我的库的代码者,使用的crt库必须满足XXX要求,必须自己测试YYY”,只是为了你自己可以少写一个 op delete[]?
这不是程序库开发者的态度。
还有两个小问题。
C* pc = static_cast<C*>(malloc(sizeof(*pc));
new (pc) C; // 编译错误
C* pc2 = new (std::nothrow) C; // 编译错误
当然, 你还是可以说你绝对不会用这种东西, 你是实用主义嘛。
但是你的库的使用者呢?
“出发点只是想找到一个经过验证的(大的、成功的产品使用过的)简便的工具”
你觉得这可以说明该产品中的每个细节都是无可挑剔的么?
越是大的产品,测试越不容易,更不容易暴露其中的问题,同时也许忽悠客户也更容易。
确实没有任何事物都是完美的,但不能连追求完美的心都舍弃了。
同时,从实用角度出发,让该库变得更完美,所付出的代价非常小,“按规则”办事就可以了,10来行代码的事,何乐而不为?
规则可以见《EffCpp》或者《C++CodingStandard》。
re: 技术回归01-Windows内存分配工具 OwnWaterloo 2009-06-03 21:30
@万连文
某某牛库是哪个库?
其实跟有没有库这样做没关系,跟该库牛不牛也没什么关系。
不能跟着别人错。
底层实现是HeapXXX?
其实跟底层实现到底是什么没关系。
C++标准没要求底层实现怎么做, 但是要求重载operator new必须有其对应形式的operator delete重载。
跟测不测试也没关系。
一次不带TT不会怀上不等于次次都不会怀上。
一个编译器上测试成功,不等于每个编译器都能测试成功。
在某个编译器上能测试通过,并不能证明或证伪。
编写operator new/delete要遵守一些规范。
HeapAlloc能否处理 size=0?
HeapAlloc分配失败时的new_hanlder处理?
对其他形式new的隐藏?
"重载"(而不是覆盖全局标准)op new时,如果不提供相应形式的op delete,是否也能正确工作?
与其在不同平台,不同编译器,甚至是相同编译器的不同版本下进行测试,不如一开始就按照标准形式编写。
re: 技术回归01-Windows内存分配工具 OwnWaterloo 2009-06-03 16:51
operator delete[]呢?
re: delete operator OwnWaterloo 2009-05-10 21:46
re: delete operator OwnWaterloo 2009-05-10 21:42
这样写是不正确的。
new操作符的含义是:
1. 调用相应的operator new分配内存
2. 在该内存上构造对象
delete 操作符执行相反的工作。
1. 调用对象的析构函数
2. 调用operator delete释放内存。
如果只调用operator delete, 对象析构函数将得不到调用。
re: 最简单的foreach实现(VC & GCC) OwnWaterloo 2009-05-08 12:46
同时…… 非常不明白 ……
为什么很多C++程序员(甚至是许多老手)都喜欢使用下划线开头的标识符……
这是个非常不好的习惯……
re: 最简单的foreach实现(VC & GCC) OwnWaterloo 2009-05-08 12:42
-------- -------- 引 -------- --------
这里有一个特殊的考虑,就是container有可能是一个临时对象,或者是某个函数的返回值。为了不对容器进行复制,利用了一个不太为人所知的C++特性,就是临时变量在存在引用时,生命期会由引用变量决定。这样保证在进行循环时始终有效。
-------- -------- 引 -------- --------
函数返回值就是临时对象的一种吧?
这个特性更准确描述应该是:
const 引用可以绑定到一个临时对象上,
临时对象的生命周期将延长至const引用超出作用域。
临时对象原本的生命周期仅到产生临时对象的完整表达式结束。
-------- -------- 分割线 -------- --------
是否可以考虑这样修改?
#define foreach(var, container) \
{ \
/... \
}
——1是可以避免临时对象的生命周期被延长到不需要的地方
——2是可以避免一个bug:
#define RANDOM_VAR(name, line) name ## line
这个宏不会以你想想中的样子工作。
至少要改成:
#define RANDOM_VAR(name, line) RANDOM_VAR_(name,line)
// 交给另一个宏
#define RANDOM_VAR_(name,line) name##line
// 才能启动rescan机制,将__LINE__展开
——3. 如果让foreach_helper有一个到container的const引用, 也就不需要单独的RANDOM_VAR去提升container的生命周期了。
Run-Time Check Failure #2 - Stack around the variable 'version' was corrupted。
这个错误信息描述不太准确。
其意思是,msvc在debug下为栈上自动变量周围分配了一些保护空间。
如果发生栈溢出, 就会写到保护空间上去。
这样, 栈溢出就能被检查出来, 并且告诉程序员, 某个变量附近的栈空间被破坏(腐坏?)了。
所以要重现这个错误只要这样:
int a[1212];
a[1986] = 0;
或者, 楼主的代码与下面更类似:
int i;
(&i)[ 1 ] = 0; // 取i的地址, 将其作为数组传递给fread。
// 但其实这个“数组”, 只有一个元素。 也会发生溢出
要修改, 要么一次只读取一个version。
要么将version改到合适大小(10就能保证一定不溢出吗?)
re: WCHAR我不再惧怕了 OwnWaterloo 2009-04-28 22:40
@shongbee2
#include <locale>
wcout<<L"汉字";
assert( !wcout );
wcout.imbue(locale("chs"));
wcout.clear();
wcout<<L"汉字";
re: 过来开个坑 OwnWaterloo 2009-04-25 16:10
终于游说成功 ……
哪不方便? 网易我没写过……
不过不支持评论rss或者通知比较不爽。。。
@vitacy
1. C标准对默认实际参数提升规则有明确规定。
也就是说, 带有可变长参数列表的函数, 绝对不会接受到char类型的实际参数。
2. C标准对va_arg是否自动对齐没有任何说明。
你说的va_arg(va_list,type)是自动对齐, 只是在你的编译器上。
并不是所有编译器都能自动帮你完成这个工作。
在所有C实现上, 能保证第1点, 但不能保证第2点。
依赖于第2点, 代码就依赖于特定编译器。
你说va_arg(ap,type)是自动对齐, 证明你有研究过。
喜欢作这些研究的, 都是聪明的家伙。
但聪明的家伙总喜欢不按规矩办事。
在gcc (GCC) 3.4.2 (mingw-special)中, type使用char, 会得到严重的警告:
`char' is promoted to `int' when passed through `...'
(so you should pass `int' not `char' to `va_arg')
note: if this code is reached, the program will abort
它会直接挂掉你的程序,来约束你必须按规矩办事。
re: 查看源文件预处理结果 OwnWaterloo 2009-04-21 14:45
将需要处理掉的那部分单独copy出来可以吗?
re: std::endl 是什么? OwnWaterloo 2009-04-18 20:58
class slt_like_ostream {
slt_like_ostream&
operator<<(std::ios_base& (*pf)(std::ios_base& );
template< class C, class T >
slt_like_ostream&
operator<<(std::basic_ios< C,T>& (*pf)(std::basic_ios< C, T>&);
template< class C, class T >
operator<<
(std::basic_ostream< C,T>& (*pf)(std::basic_ostream< C,T>&);
};
这是stl对ostream的规范。
如果不实现这些规范, 不能与stl的其他组件(如std::endl)合作也是理所当然的。
re: 自己实现的memcpy OwnWaterloo 2009-04-18 20:27
还发现一个问题……
void* my_memcpy(void *dst, /* const */ void* src, int size);
re: 自己实现的memcpy OwnWaterloo 2009-04-18 19:08
re: 自己实现的memcpy OwnWaterloo 2009-04-18 15:30
没有考虑内存对齐。
re: ACM模板之—循环队列(模板类) OwnWaterloo 2009-04-03 18:43
指针算术
re: ACM模板之—循环队列(模板类) OwnWaterloo 2009-04-03 11:58
简单的说, 假设你想查看前1212个元素,应该写 :
test.element, 1212。
re: ACM模板之—循环队列(模板类) OwnWaterloo 2009-04-03 11:55
T arr[sz];
watch中写arr。 watch会将arr认为是数组, 并且可以让你展开,查看特定元素。
T* p;
watch中写 p。 watch会将p认为是指针, 只能展开1项, 查看其值。
watch中写 p,n。 watch将认为p是一个数组的首地址, 并为你展开前n项。
re: istringstream类研究 OwnWaterloo 2009-03-25 18:48
@abilitytao
那直接就有 iostream streambuf exception stdexcept 这些文件咯?
它们的文件名都超过8个字符。
我这里没有…… 所以我怀疑是vc6 for dos……
我也有vs2008 …… 不过还有固执的人在使用vc6 …… 所以尽可能的提供支持……
re: istringstream类研究 OwnWaterloo 2009-03-25 13:20
@abilitytao
sorry, 刚才语气有点过激。
希望楼主能解答我的问题, 再次感谢~~
re: istringstream类研究 OwnWaterloo 2009-03-25 12:31
@abilitytao
我还不知道iostream属于标准库吗?
我只是想问下楼主的vc6的版本?
Microsoft Visual Studio\VC98\Include下的文件是大写还是小写?
有没有8字符限制?
谢谢~
re: istringstream类研究 OwnWaterloo 2009-03-24 23:46
以上程序在vc6.0上运行正常?
我这里的vc6, 会报很多头文件缺失。
比如iostream 会缺少streambuf stdexcept exception
要自己写这3个文件, 分别再include STREAMBF STDXCEPT XCEPTION
总之, 我这里的vc6的include中的头文件, 名字全是大写,而且都不超过8个字符。
我怀疑我用的是不是vc6 for dos 。。。。
re: 对malloc的返回值应该如何转型 OwnWaterloo 2009-03-17 22:56
@C++ Beginner
如果一个用户自定义类型C,
有一个可以通过单个类型为T的参数进行调用的构造函数,
那么,该构造函数就定义了一个T到C的转换。
如果该构造函数是explicit的,T到C的转换是显式转换。
如果该构造函数不是explicit,T到C的转换是隐式转换。
例如:
class string {
char* content_;
explicit string(const char* source,int length=-1)
:content_(0)
{
if (length==-1)
length = static_cast<int>(strlen(source));
content_ = new char[length+1];
strcpy(source,content_);
}
};
这个构造函数可以通过单个参数调用(第2个参数有默认值),所以这个构造函数定义了一个 const char* 到 string 的转换。
如果有explicit,那么该转换必须是显式转换:
string s = static_cast<string>("hello");
如果没有explict,该转换可以是隐式转换:
string s = "hello";
上面说错了,这种转换确实会调用构造函数。