C++ 关键字浅谈
这里有一个游戏:要求写一个符合C++标准的程序,包含至少十个连续而且不同的关键字。连续是指不能被标识符、运算符、标点符号分割。注意这里的“不同”要求,别想用
int main() { return sizeof sizeof sizeof sizeof sizeof sizeof sizeof sizeof (int); }
这个交卷,而且这个可以任意长。动动脑经,应该是可以想出来的。我们从很久很久以前(long long ago)开始吧,
unsigned long long int ago;
const volatile unsigned long long int ago;
extern const volatile unsigned long long int ago;
extern inline const volatile unsigned long long int f();
template extern inline const volatile unsigned long long int operator *(const Type&);
template extern inline const volatile unsigned long long int operator and(const Type& lhs, const Type& rhs); // 如果允许运算符&变成关键字and
我们强调了不同的关键字,所以只好用 long int 而不是 long long int。
typeid 也可以级联,与 sizeof 不同的是,必须添加括号。如果参数是表达式而非数据类型,sizeof 可以不用加括号。new 则没有这个限制。
#include <typeinfo> int main()
{
const std::type_info& info = typeid(typeid(typeid(typeid(int))));
return ;
}
C++规范里还要求使用 typeid 关键字的时候必须 #include <typeinfo>,否则任何使用到的地方都是 ill-formed。new 有时候也需要 #include <new> 头文件。
sizeof new const volatile signed long int();
限定不同的关键字,目前最好的答案是:
int main()
{
if(false);
else
do
throw sizeof new const volatile signed long int();
while(false);
return ;
}
spoiler alert
回到正题,C++ 诞生于1983年,现在有很多的关键字了,这里有详细的列表。
C++ 的一些运算符和标点符号需要 ISO 646 的代码集之外的字符:{, }, [, ], #, \, ^, |, ~。要能够使用不存在这些字符编码的字符集(如德国的 DIN 66003),C++定义了两种替代方案:额外的关键字对应这些操作符,使用 ISO 646 兼容的字符构成的特殊的两元组或三元组解释成一个非 ISO 646 字符。
首选 | && | &= | & | | | ~ | ! | != | || | |= | ^ | ^= |
替代方案 | and | and_eq | bit_and | bitor | compl | not | not_eq | or | or_eq | xor | xor_eq |
使用两元组和三元组可能会遇到一些奇怪的问题,而且也影响代码阅读。C++标准打算在C++17版本废除掉三元组符号 ??< ??> ??( ??) ??= ??/ ??' ??! ??-。两元组 <: 会被替换成 [ 符号,于是 std::vector<::std::string> 会被错误的当成 std::vector[:std::string> 对待。现在的键盘都有这些符号,所以不用用他们的替代符号。毕竟符号比字符串易懂,想想数学运算中的加减乘除符号如果用 add/subtract/multiply/devide 英文替换表示,读起来就不舒服,这也是为什么C++引入操作符重载,矩阵的运算可以直接写 (A+B)/(C*D); 而不是 divide(add(A, B), multiply(C, D));
基本数据类型 void bool char wchar_t short int long unsigned float double,布尔值 true false,以及 C++11 新增的 char16_t char32_t nullptr 关键字。
char、signed char、unsigned char 是不同的类型,这个需要注意一下。GCC 编译的时候,可以用编译选项 -fsigned-char 或 -funsigned-char,它们分别将 char 指定为 signed char 或 unsigned char。很多程序直接写char,希望它是有符号的或者无符号的。程序员喜欢简短,跟 int 关键字一样,不写就默认有符号的类型;但有时候处理二进制流,表示成[0, 256)区间的整数。
看到这个表格,原来整形有这么多。其实我更喜欢用简短的 uint8_t/int8_t/.../int32_t 等。你会看到很多代码工程都自己定义了一套整形数据,避免 16位整形的程序移植到32位系统、32位整形的程序移植到64位系统 出现问题。而且C++ 对关键字的修饰顺序也没有要求,这让一些程序员甚是纠结。
GNU 的 STL 库也有这种顺序的 long unsigned int
#ifndef __SIZE_TYPE__
#define __SIZE_TYPE__ long unsigned int
#endif
true/false 的类型是 bool,那 nullptr 的类型是什么?
typedef decltype(nullptr) nullptr_t;
这种类型定义妙不可言,也横空推出新的关键字 decltype。如果两个重载的函数 fun 可以接受不同的指针类型,比如 void fun(int*); void fun(float*); 那么编译 fun(NULL) 会有二义性错误。不妨再定义一个 std::nullptr_t 空指针类型的函数 void fun(std::nullptr_t nullp),这次 fun(NULL) 编译失败但是 fun(nullptr) 可以通过。
wchar_t 用来表示一个 Unicode 字符集中的编码,在 Windows 上是 UTF-16,类 Unix 系统上是 UTF-32。sizeof(wchar_t) 是 implementation defined,移植性差。一般在Windows上是2个字节,在类 Unix 系统上是4个字节。Windows 接受了宽字符并使之成为标准,可以看到许多Windows API 有两个版本,functionNameA 和 functionNameW 分别对应ANSI版本和宽字符版本。这篇博客列举了使用wchar_t可能犯的错误。
C规范中并没有写明宽字符 wchar_t 的具体类型,与编译器实现相关,可能8/16/32位,也可能是signed 或者 unsigned。关键在于选用的编码字符集,注意字符集(Charset)与字符编码(Character Encoding)的区别,ASCII/GBK/BIG5/GB18030 是字符集,Unicode 是字符集。当时各个国家都做了自己的编码方案,中国有 GBK/GB18030/BIG5 等,这在国内没有问题,但是网络遍及世界各地,外面的人访问就出现乱码。于是 Unicode 应运而生。Unicode 字符集有 UTF-7/UTF-8/UTF-16/UTF-32 这几种编码。
推荐使用 Unicode 字符,不推荐使用 wchar_t,取而代之使用固定长度的 char16_t/char32_t 类型。
ISO/IEC 10646:2003 Unicode 标准 4.0 里讲到:
"The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compiler should not use wchar_t for storing Unicode text. The wchar_t type is intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers."
C 语言关键字 int 是用的最多的,我经常觉得 short/long 的修饰让 int 显得多余。short int 与 short 语义一样,long int 与 int 语义一样。long 与 short 是相对来讲的,于是又出现了 long long int 这一类型。long long 是1995年提议加没加成,C++ 因为 C 没有加所以也不肯加入。很多编译器都自己实现了,10年之后,大家觉得有必要标准化了。(说不定将来某一天,整数的计算范围需要扩充到 128 位,于是要唤出 long long long long int?好囧)个人觉得,程序语言诞生的时候,就应该尽量让关键字语义正交,虽然标准规定了 sizeof(short) <= sizeof(int) <= sizeof(long),但是很多编译器还是将 int 与 long int 等同看待。C 语言可移植好不由争辩;Java 很聪明,直接规定了各自的长度。short/int/long 分别为 2/4/8 个字节。
有一个头文件 <stdint.h> 专门定了各种整形数 int8_t/int16_t/int32_t/int64_t 等,还有 unsigned 类型。其实 short/long/signed 都是形容词,int 是名词,所以声明整形没有以 int 结尾也是对的,与其写 long long int,不如写 long long,甚至 int64_t。我也想过如果 sizeof(int) == sizeof(long int),在 32 位机器上,要么 long 多余,要么 int 多余。然后我想到了 long double 类型,觉得还是 int 多余吧。
选取关键字要尽量做到语法正交,尽量能表达所有的意思,小部分可以留给扩展。从 C++11 的改变可以看出,尽量不添加新的关键字,双中括号扩展 [[]] 和右值符号 &&;不得已时添加新的关键字 alignas/alignof/thread_local 等。对差不多不用的关键字回收,auto 重新焕发光芒,template 能做的活,auto 现在也可以简单完成。
添加新的关键字的时候,需要考虑几乎不会在历史代码中用到的。一些上下文相关的(contex-sensitive)关键字 final,override 的出现。它们不算关键字,但是放到函数末尾可以让编译器查错。可想而知,如果像 final override 这样常见的单词选入关键字,会有多少历史代码需要修改。很显然,final 和 override 是从 Java 语言中学过来的。Python 从 2.x 升到 3.x,各种不兼容,让人对这个语言又爱又恨,虽然有帮助迁移代码的文档和工具。
因为 final 与 override 是上下文相关的,所以你这么写代码也会编译通过。
class Base
{
public:
virtual int override(int )
{
std::cout << "please override me" << std::endl;
return ;
}
}; class Fun: public Base
{
public:
virtual int override(int ) override final
{
int override = ;
return override;
}
}; int main()
{
int me = 0x3e;
Fun hey;
hey.override(me); return ;
}
在 C++11 之前,C++ 标准交了很多东西给编译器自行处理,比如是否自行产生构造函数,内存对齐,RVO 优化,enum 的类型等等,现在都可以显式要求,避免各搞各的一套。enum 的类型是 implementation defined,很多编译器都是用能容纳的最小的整形范围来表示。所以你会在微软的很多代码里看到很多这样的写法:
typedef enum D3DTEXTUREADDRESS {
D3DTADDRESS_WRAP = ,
D3DTADDRESS_MIRROR = ,
D3DTADDRESS_CLAMP = ,
D3DTADDRESS_BORDER = ,
D3DTADDRESS_MIRRORONCE = ,
D3DTADDRESS_FORCE_DWORD = 0x7fffffff
} D3DTEXTUREADDRESS, *LPD3DTEXTUREADDRESS;
最后一个 enum 常量是 XXX_FORCE_DWORD = 0x7fffffff,对其取值 sizeof(D3DTEXTUREADDRESS) 长度固定为 4。
对齐本来是语言设计者想掩盖的细节,不过在C++11编程方式越发复杂的情况下,提供给用户更底层的手段往往是必不可少的。在一些情况下,用户虽然不能保证总是写出平台无关,或者说各平台习惯你能最优的代码,但只需要改造 alignas 之后的对齐值参数就可以保证程序的移植性及性能良好,也不失为一种好的选择。而 C++11 对对齐方式的支持从语法规则到库,基本上考虑了各种情况,可以说是相当完备的。
template <typename T>
class alignas(sizeof(T)<<) Color
{
T r, g, b, a;
};
让关键字增加功能。以前 default 和 delete 只有一种用途:default 就是 switch 语句里的默认分支,delete 就是释放内存。现在都多了一种用法 = delete 表示删除函数,= default 表示使用编译期默认产生的。以前 using 只能与 namespace 为伴,而现在,typedef 所干的活,全部可以接手过来,而且在写法上更直观易懂。以前写 typedef long long int int64; 现在你可以写 using int64 = long long int; 怎么样?数据类型也可以用等号“赋值”了。
C++11 出来后,你不用看编译器的脸色行事了。这里不需要定义构造函数,好让编译器自己生成;那里需要定义构造函数,否则编译器会做 shallow copying。现在你可以显示指示编译器怎么做。
class noncopyable
{
private:
noncopyable(const noncopyable& ); // not defined
noncopyable& operator=(const noncopyable&); // not defined
};
之前,我们不想让对象之间赋值,会讲赋值构造函数和 operator = 限制为 private,并不提供定义。现在我们有更好的写法:
class noncopyable
{
public:
noncopyable(const noncopyable& ) = delete;
noncopyable& operator=(const noncopyable&) = delete;
};
声明为 private 可以阻止被调用。故意不实现这些函数,意味着如果外部通过成员函数或者 friend 类想访问它们,虽然编译可以通过,但是链接的时候会因未定义的符号而报错。在 C++11 里,情况就不一样了。使用 = delete 表示编译期不会产生这个方法,所以这个可以扼杀在编译期,不用推迟到链接的时候。虽然这里的访问权限对 C++11 不重要,但一般来说,标记 delete 的函数最好声明 public,而不是 private。因为有的编译器在检查成员函数的调用时,只报访问权限错误(错误如下)。很显然,这里 delete 才是重点,或者说错误的优先级高些。当然,并不是只有成员函数才能 delete,非成员函数和模版实例化的函数也是可以的。相比 C++98 而言,算是一项改进。
error: ‘pea::Log::Log(const pea::Log&)’ is private
Log(const Log& log) = delete;
提醒一下,using namespace std; 不要写在 .h 文件里,要写也是写在 .cpp 文件里。出于头文件会被其他头文件包含的可能,污染命名空间,但是 .cpp 文件不会。除非你故意想 #include "XXX.cpp" 这么写。在cocos2d-x 里的 class HelloWorld 里面添加方法 void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event); 会编译不过,报错如下:
1>classes\HelloWorldScene.h(17): error C2653: 'EventKeyboard' : is not a class or namespace name (..\Classes\AppDelegate.cpp)
1>classes\HelloWorldScene.h(17): error C2061: syntax error : identifier 'KeyCode' (..\Classes\AppDelegate.cpp)
1>classes\HelloWorldScene.h(17): error C2653: 'EventKeyboard' : is not a class or namespace name (..\Classes\HelloWorldScene.cpp)
1>classes\HelloWorldScene.h(17): error C2061: syntax error : identifier 'KeyCode' (..\Classes\HelloWorldScene.cpp)
1>classes\HelloWorldScene.cpp(72): error C2276: '&' : illegal operation on bound member function expression
其实修改很简单,添加 EventKeyboard 和 KeyCode 所在的命名空间就好了。
void onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event* event);
然而在 HelloWorldScene.cpp 里不用添加,因为开头有这么一句 USING_NS_CC; 也就是 using namespace cocos2d; 引入了 cocos2d 所有的东西。
void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
//TODO
}
virtual 关键字用来申明虚函数,在虚函数的末尾添加 =0 表示纯虚函数。在函数名和参数可能动态变化的情况下,需要手动检查基类与派生类的函数是否一致,是否派生类的成员函数覆盖了基类的成员函数。这种枯燥的工作应该交给编译器来做的,于是 C++11 引入了上下文相关的关键字 override,在需要覆盖的地方没有覆盖,编译器就会报错。
在 C++98,空指针用字面值 0 来表示, C++11 标准出来后,最好使用 nullptr,于是有人会问纯虚函数的声明 = 0 是不是应该更正为 = nullptr,尝试了下是不行的。语法上规定必须是 0, 而不能是表达式(42 - 42),甚至 0L,0u 0x0 (clang 编译器以前支持这样的写法)等。有些人选择用宏 #define pure = 0 ,这个从声明上似乎容易识别虚函数,这样写不是很好。C++ 之父 Bjarne Stroustrup 解释了没有添加 abstract/pure 关键字。(Java 里有关键字 abstract)
Bjarne Stroustrup 在他的书 The Design & Evolution of C++, section 13.2.3 中描述
The curious =0 syntax was chosen over the obvious alternative of introducing a new keyword pure or abstract because at the time I saw no chance of getting a new keyword accepted. Had I suggested pure, Release 2.0 would have shipped without abstract classes. Given a choice between a nicer syntax and abstract classes, I chose abstract classes. Rather than risking delay and incurring the certain fights over pure, I used the tradition C and C++ convention of using 0 to represent "not there." The =0 syntax fits with my view that a function body is the initializer for a function also with the (simplistic, but usually adequate) view of the set of virtual functions being implemented as a vector of function pointers.
= 0 似乎让人迷惑,认为纯虚函数就是未实现的函数,以为是将该函数指针置空(nullptr),而实际上,纯虚函数也是可以实现的。不能在声明时实现,而是必须在外部给出定义。C++11 引入了上下文相关的关键字概念,现在开来,引入 pure 作为上下文相关的关键字,将 = 0 替换成 pure 的写法会更直观。
class Base
{
public:
virtual void fun() = ;
}; void Base::fun()
{
std::cout<<"pure virtual implementation\n";
} class Derived: public Base
{
public:
virtual void fun() { Base::fun(); }
};
这里引出另外两个话题:析构函数可以是纯虚函数,但必须给出定义,否则会出现链接错误,因为继承的类在析构的时候会调用基类的析构函数,找不到符号。纯虚函数要求非抽象子类给出实现,所以基类的构造函数最好给 protected 权限。
C++11 增加的 operator "" 的重载,用户自定义语义(user literal)限制在以下几种类型,
( const char * )
( unsigned long long int )
( long double )
( char )
( wchar_t )
( char16_t )
( char32_t )
( const char * , std::size_t )
( const wchar_t * , std::size_t )
( const char16_t * , std::size_t )
( const char32_t * , std::size_t )
发现没有,比如浮点类型只有 long double,却没有 float 和 double 类型,为什么呢?假设我们有一个角度制和弧度制转换的函数语义。
constexpr long double operator"" _deg ( long double deg )
{
return deg*M_PI/;
}
我们要表达 M_PI 弧度时候,可以写成 180_deg ,注意 180 和 _deg 是一个整体,之间不能有空格。(就像 C/C++ 语言内的后缀语义 long int degree = 180L; float pi = 3.14159265f 一样)。如果要区分 float、double、long double 数据类型,我们的定义应该是这样的:
float radian1 = 180f_deg;
double radian2 = 180_deg;
long double radian3 = 180L_deg;
很显然,编译器会把没有空格的合法字符当成一个单词(token)解析,于是 f_deg 变成了一个单词,前面也说了 f 与 _deg 之间不能有空格,所以我们无法满足不同浮点类型的重载,也包括整数类型。为了不截断或窄收,于是采取最大表示范围的类型,整形用 unsigned long long int,浮点类型用 long double。整形是 long long int 而不是 unsigned long long int 是因为有符号和无符号数相加减,会扩充到无符号类型。这里似乎暗示了 unsigned long long int 是最大范围的整形,所以应该不会出现 128 位的整形。
尽量让计算或可能发生的错误推前到编译期而不是运行期,在 C++11 增加了新的关键字 static_cast、constexpr。boost 库里面有模拟 static_cast 的功能。
之前我们用宏定义 FOURCC
#define MAKE_FOURCC(ch0, ch1, ch2, ch3) \
((uint32_t)(uint8_t)(ch0) | \
((uint32_t)(uint8_t)(ch1) << ) | \
((uint32_t)(uint8_t)(ch2) << ) | \
((uint32_t)(uint8_t)(ch3) << )) \
现在我们可以直接用 constexpr 函数来写,而不是类型不安全的宏了。因为是编译器计算出值,所以算出来的整形值可以直接用于 switch case 语句中而不会出错。
constexpr uint32_t makeFourCC(uint8_t ch0, uint8_t ch1, uint8_t ch2, uint8_t ch3)
{
return static_cast<uint32_t>(ch0 | (ch1<<) | (ch2<<) | (ch3<<));
} constexpr uint32_t RIFF = makeFourCC('R', 'I', 'F', 'F');
constexpr uint32_t WAVE = makeFourCC('W', 'A', 'V', 'E');
constexpr uint32_t FMT_ = makeFourCC('F', 'M', 'T', ' ');
constexpr uint32_t DATA = makeFourCC('D', 'A', 'T', 'A');
让派生类不要继承父类的行为,大概有三种做法。
1. virtual void fun1() {}
2. virtual void fun2() { assert(false); }
3. virtual void fun3() = 0;
这些写法我都遇到过,fun1 实现留空,表示派生类可以覆盖其行为;fun3 纯虚函数,表示派生类必须覆盖其行为;而 fun2 如果没有覆盖,在运行时断言失败。
很显然 fun2 的做法不是很好,错误要等到运行时才能发现。
类型转换关键字 const_cast / dynamic_cast / reinterpret_cast / static_cast
不要用C的带括号的强制转换。不要在指针和整形之间转换,也不要在数据指针和函数指针之间转换。类型之间转换时,首先考虑使用 static_cast。整形到 enum 枚举类型、浮点数到整形用 static_cast。从 void* 类型转换到特定的指针类型,虽然 static_cast 与 reinterpret_cast 都能用,最好还是用 static_cast。在不相关的指针类型之间转换时,用 reinterpret_cast,这个相当于C语言里面的转换。const_cast 不要被名字迷惑了,它是可以 cast 掉 CV-qualifier,而不仅仅是 const,可以是 volatile 修饰的类型。
// Possible implementation of std::addressof in <memory>
template<typename T>
T* addressof(T& arg) noexcept
{
return reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char&>(arg)));
}
上面是C++11标准里的 std::addressof 的实现。注意这里的hack技巧,最里层需要有const volatile关键字。reinterpret_cast 转换可以增加 const volatile 修饰符,但不能移除。所以如果 arg 是 const 变量的话,reinterpret_cast 就会编译失败。
对于函数传入的指针或引用,如果不会修改其内容,尽量用 const 修饰这个参数。C语言中释放内存的函数是 void free(void *ptr);,释放本来是不会修改指针指向的内容的,而是让操作系统回收分配的内存。函数签名似乎应该为 void free(const void *ptr);,这样可以直接释放 const 指针类型而不用 const_cast 转换一次。但是从另一方面讲,申请内存一般就会修改内存,修改就不能直接用 const 修饰,谁申请谁释放,释放内存也就不是 const 指针的责任了。
基类到派生类的转换,需要用到 dynamic_cast,我们称之为下转(downcast)。指针下转失败为空 nullptr,引用下转失败则抛出 std::bad_cast 异常。在 C++11 的 noexcept 出现之前,C++ 的异常处理机制不是很好使,很多程序员也是尽量不去碰。在含有大量层次继承关系的游戏或对性能有要求的一些工程里,会关闭 C++ 的 RAII (Run-Time Type Information) 机制。做法是 debug 版本开启检查类型安全,release 版本关闭运行时的查找以提升性能。
template <typename To, typename From>
To downcast(From p)
{
#ifdef NDEBUG
return static_cast<To>(p);
#else
To to = dynamic_cast<To>(p);
assert(to != nullptr);
return to;
#endif
}
C++ 十几年的时间没有动静,造就了 boost 优秀库的出现。又从较自己晚出身的语言身上也学到了很多,比如 Java 类的成员在定义的时候给定默认值,委托构造函数(delegate constructor)、Python 的原生字符串常量,也算方便了程序员对 C++ 字符串的学习和使用。
C++ 关键字浅谈的更多相关文章
- 5.C#知识点:ref和Out关键字浅谈
首先我们要知道ref和out在C#里面是什么? 答:它们俩是C#里面的关键字. 他们俩是干啥的呢? 答:他们俩是方法参数的修饰符号,一但使用,方法定义和方法都用都要使用这个关键字,这一点是死规定. 好 ...
- [UE4]C++中extern关键字浅谈
变量声明和变量是有区别的 extern int i; //只是声明i而非定义i int j; //声明而且还定义了j 任何一个显式初始化的声明都将成为定义,而不管有没有extern,extern语句一 ...
- C#知识点:ref和Out关键字浅谈
首先我们要知道ref和out在C#里面是什么? 答:它们俩是C#里面的关键字. 他们俩是干啥的呢? 答:他们俩是方法参数的修饰符号,一但使用,方法定义和方法都用都要使用这个关键字,这一点是死规定. 好 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 转载 浅谈C/C++中的static和extern关键字
浅谈C/C++中的static和extern关键字 2011-04-21 16:57 海子 博客园 字号:T | T static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性.ext ...
- 浅谈Java中的final关键字
浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- Linux特殊符号浅谈
Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...
- 浅谈JAVA集合框架
浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...
随机推荐
- 这两天遇到iphone使用app store下载免费软件,必须验证付款信息才能购物是怎么回事???
答案: 在你这台设备上再设置一下,具体方法是:1.点设置进入2.点iTunes Store 和App Store 3.点 Apple ID ,如果没设置,设置一下,如果有的,再点击 4.出现一上选择的 ...
- [Unreal]学习笔记之材质说明
取消蓝图中的连接线:Alt+鼠标左键 在蓝图中,通过按住1,2,3,4加鼠标左键,可以快速生成1,2,3,4维的向量 材质和材质实例的区别:使用一个母材质,可以创建出多种场景中的材质实例:每次修改母材 ...
- Python 下载 tushare 数据,然后调用 C++ DLL 计算 wMA 存入本地 csv 文件再 python 读取
CMakeLists.txt project(wMA) add_library(wMA SHARED wMA.cpp) wMA.h #pragma once #ifndef WMA_WMA_H #de ...
- sublime 安装插件GitGutter报错,git binary cannot be found等等
今天给sublime text安装插件GitGutter的时候,居然报错了,网上查找了下解决方法,在此记录下.因为本博主的电脑是windows的,所以这里只能提供windows的方法啦. 解决方法很简 ...
- 微软压力测试工具 web application stress
转自 http://www.cnblogs.com/tonykan/p/3514749.html lbimba 铜牌会员 这里给广大的煤油推荐一个web网站压力测试工具.它可以用来模拟多个用户操作网 ...
- Fedora20-32bit cross-compiling arm-linux-gcc4.3.2
目录 0 前言 1 安装arm-linux-gcc-4.3.2 2 配置 nfs 服务器 0 前言 之前在 fedora 64bit 上建立交叉编译,但由于4.4.3版本需要另装用于gdb-serve ...
- vtkTubeFilter实例
filter that generates tubes around lines vtkTubeFilter is a filter that generates a tube around each ...
- spring实例化bean的三种方式
公共使用的实体
- spring 上传 下載文件
1,spring配置文件添加文件上传配置 <!-- 上传文件 --> <bean id="multipartResolver" class="org.s ...
- hdu 4329
problem:http://acm.hdu.edu.cn/showproblem.php?pid=4329 题意:模拟 a. p(r)= R'/i rel(r)=(1||0) R ...