enum
传统使用方法
enum Color { red , green, blue };
void testOldEnum() {
Color r = red;
switch (r) {
case red:
std::cout << "i'm red\n";
break;
case green:
std::cout << "i'm green\n";
break;
case blue:
std::cout << "i'm blue\n";
break;
default:
std::cout << "what?\n";
}
//enum可以直接赋值给一个整型
int a = r;
}
这会导致一个问题,如果再定义一个enum
enum Hate{red, good, blue};
编译器好会报错。因为两个enum中都有red。有重复,就会让编译器分不清。这就会导致你引用的库里面如果使用了enum,你就不能写含有重复元素的enum。
enum class
cpp 11对enum进行的扩展
//long long 用来说明enum class的大小是long long那么大
//如果不写,默认用int大小来代表enum class
enum class NewColor : long long { Red, Green = 20, Blue };
void testNewEnum() {
NewColor r = NewColor::Blue;
switch (r) {
case NewColor::Red:
std::cout << "red\n";
break;
case NewColor::Green:
std::cout << "green\n";
break;
case NewColor::Blue:
std::cout << "blue\n";
break;
}
//enum class不能直接赋值给int类型。需要进行static_cast强制转换
int a = static_cast<int>(r);
}
enum class还可以用于函数传参
之前说过,用bool类型传参,会降低代码的可读性,如果没有文档辅助,可能会引起别人对代码含有的无解。因此可以用enum class来进行函数参数传递
enum class IsGood {
Yes,
No
};
enum class IsHero {
Yes,
No
};
enum class IsMom{
Yes,
No
};
void show(IsGood, IsHero, IsMom) {
}
void show(bool isGood, bool isHero, bool isMom) {
}
explicit——阻止隐式转换
struct A {
A(int) {}
A(int, int) {}
//使得A可以默认的转换成int
operator int() const { return 0; }
};
struct B {
explicit B(int) {}
explicit B(int, int) {}
explicit operator int() const { return 0; }
};
void handleA(A a) {}
void handleB(B b) {}
void testS(const std::string& s) {}
void testExpl() {
A a1 = 1; // 等价于 A a1 = A(1);
// B b1 = 1; //B不能那么写,因为explicit阻止编译
A a2(2);
B b2(2); // OK
A a3 = { 4, 5 }; // 等价于 A a3 = A(4,5); A{4,5};
//B b3 = {4,5}; // 这样的不允许的
int na1 = a1; // OK,因为operator int() const { return 0; }
//int nb1 = b2; //无法通过编译
int na2 = static_cast<int>(a1); //显示转换,可以的
int nb2 = static_cast<int>(b2); //显示转换,可以的
A a4 = (A)1; //ok
B b4 = (B)1; //ok,这是强转,明确告诉编译器要转,所以可以
handleA(a1); //ok
handleA(1); //可以编译通过,因为A可以通过int构造出来
handleB(b2); //ok
//handleB(2); //编译失败
}
namespace
namespace XGroup {
class A {int value;};
}
namespace YGroup {
class A {int value;};
class B {};
}
class A {
int value;
A() { throw 1;}
};
void testNamespace() {
XGroup::A a;
YGroup::A b;
A c;
}
void testNamespace2() {
namespace CGroup = XGroup;
CGroup::A a;
using YGroup::B; //简化namespace前缀
B b;
YGroup::A aa;
using namespace YGroup; //直接把YGroup的全都拿来用,不过容易造成歧义
A c;
}
namespace可以没有名字
//namespace可以没有名字
//astring只在当前文件中有效
namespace {
std::string astring("long");
}
noexcept
告知编译器我们不会抛出异常,用以方便编译器做出一些优化处理
void f() noexcept {}
如果声明了noexcept的函数抛出了异常(比如函数里面声明一个A的对象a,a在构造的时候抛出了异常,导致函数抛出异常),此时会调用函数terminate(),用以退出函数,进而导致程序挂掉。
设置noexcept失效的方法
void f() noexcept(false) {}
nullptr
template<typename T, typename U>
void func(T t, U u) {
t(u);
}
void nullPointer(int* a) {
std::cout << "i'm a pointer\n";
}
void testNullPointer() {
nullPointer(0); //ok——0可以转化成一个指针,c++中0可以转化成一个指针
nullPointer(NULL); //ok——c中null是(void*)0 /c++中null是0
nullPointer(nullptr);
func(nullPointer, nullptr); //ok
//c中可以,cpp的模板对于类型检查更为严格
func(nullPointer, 0); //不可以,因此会把0推到成int,所以不可以
func(nullPointer, NULL); //不可以
func(nullPointer, (int*)0); //可以
}