本文主要探讨c++相关关键字的使用。
char
char默认是unsigned/signed取决平台,wchar_t宽字符:用于Unicode编码(超过一个字节),用wcin和wcout输入输出,字符串为wstring
char8_t(20),char16_t(11起),char32_t(11):指定占用字节数且是无符号,字符串类u8string,u16string,u32string(20)
逻辑与位运算
and(&&),or(||),not(!),bitand(&),bitor(|),xor(^)and_eq(&=),or_eq(|=)xor_eq(^=),compl(~),not_eq(!=)
引用(&):
引用在定义时初始化(指向对象),后面不能指向其他对象,指针可在任何时候指向其他对象
引用本质:int &b = a; <==> int * const b = &a;(指针变量const化)
引用主要用在函数传参和返回值,sizeof(引用)是目标变量大小,未规定引用所占空间大小,编译器会给分配空间
enum
enum class enmu_type_name:unsigned int{MON = 1, THU, WEN};
enum enmu_type_name{MON = 1, THU, WEN};
枚举类型和值类型可以互相转换,但不能运算
inline:
定义在类声明之中的成员函数将自动地成为内联函数
类外定义inline函数,类定义和成员函数在同一头文件,否则编译无法进行置换
class A
{
public:
void Foo(int x, int y) { ... } //自动地成为内联函数,即使没有inline关键字
}
nullptr
C语言中NULL标记野指针((void *)0),C++为其他类型((int *)0 ...)
nullptr的本质
const class nullptr_t
{
public:
template<class T> inline operator T*()const {return 0;}
template<class C, class T> inline operator T C::*() const {return 0;}
private:
void operator&() const;
} nullptr={};
static_assert
C编译错误用#error输出,asser运行时错误退出
C++的static_assert静态断言编译时错误退出,
内存对齐
扩大对齐:__attribute__((aligned(n))),缩小对齐:__attribute__((packed))
alignas(n)与__attribute__((aligned(n)))相同,alignof(struct s) <==> 返回未对齐结构体大小或扩大机构体所占字节数
类型转换
typeid:返回变量,表达式,对象,的类型,返回静/动态态类型
static_cast<type-id>(exdivssion)
显示类型转换:基本类型转换,指针类型转换(空针->目标类型空针),函数类型转换(任意类型函数->void),父类和子类之间指针和引用转换(上行转换安全,下行转换不安全),不能转换掉exdivssion的const、volitale、__unaligned
dynamic_cast< type-id >(exdivssion)
Type-id必须是类指针、类引用或者void *,主用于类层次间上行转换和下行转换,类之间交叉转换
reinterpret_cast <new_type>(expression)
reintepret_cast <==> C的强制类型转换,不进行类型检查
const_cast(const_cast<type_id> (expression))
常量向非常量转化,用于添加和移除const或volatile修饰
auto(11)
自动推导出变量(对象)类型,定义时初始化,不能一次定义多个类型的不同变量
decltype:编译器推导目标表达式类型,不要求初始化
auto和decltype:
auto忽略顶层const,decltype保留const
auto作为类型占用符,decltype类似于sizeof
auto推断出引用(解引用)原有类型,decltype推断出引用
auto推断时会执行,decltype做分析
class
class是对struct扩展,数据(成员变量)和方法(成员函数)的封装,包含数据和方法的访问权限(private、protected、public)
static静态成员和方法属于class,非静态属于对象
this本质是指向当前对象的指针,未定义对象前可在方法中调用对象成员
virtual修饰class成员函数为虚函数(基类中),有接口声明没实体,可在派生类中重写(override)实现面向对象多态性
final修饰class的不能被被继承,final修饰成员的方法子类不能重写
using能让子类去声明并访问父类中private成员
operator用于运算符重载(重定义运算符)
friend不属于class的外部函数访问class内受保护的成员变量
explicit(显式)、implicit(隐式)修饰构造函数防止构造函数错误类型转换
const
const限制函数内部对类成员变量修改,mutable可突破const成员函数限制,可以修改特定成员变量
constexpr将变量值赋值给const修饰的变量
constexpr int multiply (int x, int y)
{
return x * y;
}
const int val = multiply( 10, 10 ); //const int val = 100;
export定义模板类或模板函数,在,h文件中声明,类似extern
requires用于模板参数约束
异常处理
throw(int,double,char,long,short)
函数抛出5类exception,throw()不会抛出异常noexcept替代throw()表示不抛出异常,noexcept(bool)抛出任意异常
throw异常若没有catch会向上层传递直到被catch,函数可用throw列表来标识抛出的异常
标准库exception类:bad_typeid,typeid运算是多态指针且不为NULL,会拋出异常
bad_cast,dynamic_cast多态基类对象(或引用)到派生类引用的强制类型转换若不安全会拋出异常
namespace
避免命名冲突,提高可读性和可维护性,支持模块化和封装,提高代码可靠性和扩展性
命名空间里面可以包含变量、函数、类型,不能定义在局部作用域
相同名称命名空间编译时会合并,相同名称命名空间不能存在相同变量、函数、类型的定义
未命名空间(全局变量)直接使用,命名空间(全局变量)使用 :: 域作用限定符或using关键字声明使用
函数
void func(int i,int j);C中func函数编译后符号表中为func,C++编译后符号表中为_Z3funcii所以c++中函数参数列表类型、个数可变,还可带有默认参数,c不可行
C++调用C库(使用C规则编译):extern "C"{};
demo1:
key word测试
目录结构:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.20) #最低版本要求
SET(CMAKE_CXX_COMPILER "g++") #设置g++编译器
PROJECT(KeyWord) #设置工程名
MESSAGE(STATUS "test keyword") #打印消息
ADD_EXECUTABLE(pro main.cpp) #生成可执行文件
run.sh
#!/bin/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
main.cpp
#include <iostream>
using namespace std;
int bool_test()
{
int num = 2;
bool logic = !num;
cout << boolalpha << logic << endl;
return 0;
}
int test_cite()
{
struct test
{
int num;
int &cite = num;
};
struct test s;
s.num = 1;
int tmp = 10;
s.cite = 3;
//&s.cite = tmp; //引用在定义时初始化(指向合法地址),后面不能指向其他地址,指针可在任何时候指向其他地址
cout << "sizeof(s.num) : " << sizeof(s.num) << endl;
cout << "sizeof(s.cite) : " << sizeof(s.cite) << endl;
cout << "sizeof(s) : " << sizeof(s) << endl;
cout << "sizeof(struct test) :" << sizeof(struct test) << endl;
cout << "num : " << s.num << endl;
cout << "cite : " << s.cite << endl;
const int &t = tmp;
//t = 20; //引用本质:int &b = a; <==> int * const b = &a;(指针变量const化)
return 0;
}
int test_enum()
{
enum test {ZERO,ONE,TWO};
test num; //c++ ,c: enum test num
num = ZERO;
cout << "num :" << num << endl;
cout << "enmu list :" << ZERO << " " << ONE << " " << TWO << endl;
//ZERO++; ZERO = 2; //不能赋值
enum tmp {A = 1,B = 4,C = 5};
tmp t = tmp(10);
cout << "t :" << t << endl;
return 0;
}
void func(char *p)
{
cout << "char func" << endl;
}
void func(int *p)
{
cout << "int func" << endl;
}
int test_nullptr()
{
char *pc = nullptr;
int *pi = nullptr;
func(pi);
func(pc);
cout << "c++ NULL :" << NULL <<endl;//c++ : NULL == 0, c: NULL == (void *)0
return 0;
}
int test_static_assert()
{
static_assert(sizeof(void *) == 8,"not support 64bit system ");
return 0;
}
int mem_align()
{
struct s1
{
char a;
short b;
int c;
};
struct alignas(16) s2
{
char a;
short b;
int c;
};
cout << "sizeof(s1) :" << sizeof(struct s1) << endl;
cout << "alignof(s2) :" << alignof(struct s1) << endl;
cout << "sizeof(s2) :" << sizeof(struct s2) << endl;
cout << "sizeof(s2) :" << alignof(struct s2) << endl;
return 0;
}
int test_typeid()
{
char a;
unsigned char b;
signed char c;
int d;
long e;
float f;
double g;
short h;
cout << "typeid(a).name() :" << typeid(a).name() << endl;
cout << "typeid(b).name() :" << typeid(b).name() << endl;
cout << "typeid(c).name() :" << typeid(c).name() << endl;
cout << "typeid(d).name() :" << typeid(d).name() << endl;
cout << "typeid(e).name() :" << typeid(e).name() << endl;
cout << "typeid(f).name() :" << typeid(f).name() << endl;
cout << "typeid(g).name() :" << typeid(g).name() << endl;
cout << "typeid(h).name() :" << typeid(h).name() << endl;
cout << "typeid(short).name() :" << typeid(short).name() << endl;
return 0;
}
int type_convert()
{
char a = 1;
int b;
b = a;
b = static_cast<int>(a);
cout << "b :" << b << endl;
class A
{
public:
virtual void Foo() //虚函数
{
}
};
class B : public A{};
class C : public A{};
A *c1 = new B;
B* c3 = dynamic_cast<B*>(c1); //下行转换
C* c4 = dynamic_cast<C*>(c1); //横向转换
int *pi;
char *pc;
pi = reinterpret_cast<int *>(pc);
const int n = 10;
int *t = const_cast<int *>(&n);
*t = 20;
cout << "n : " << n << endl;
cout << "*t : " << *t << endl;
return 0;
}
int test_auto()
{
int a = 5;
auto b = 6;
auto c = a;
decltype(a) e;
decltype(b) f;
decltype(c) g;
auto h = e;
auto i = f;
auto j = g;
const int num = 1;
auto tmp = num;
decltype(num) t = 8;
tmp = 2;//auto忽略const
//t = 9; //decltype可推断出const
char s = 1;
auto &s1 = s;
cout << "a type : " << typeid(a).name() << endl;
cout << "b type : " << typeid(b).name() << endl;
cout << "c type : " << typeid(c).name() << endl;
cout << "e type : " << typeid(e).name() << endl;
cout << "f type : " << typeid(f).name() << endl;
cout << "g type : " << typeid(g).name() << endl;
cout << "h type : " << typeid(h).name() << endl;
cout << "i type : " << typeid(i).name() << endl;
cout << "j type : " << typeid(j).name() << endl;
cout << "num type : " << typeid(num).name() << endl;
cout << "tmp type : " << typeid(tmp).name() << endl;
cout << "t type : " << typeid(t).name() << endl;
cout << "s1 type : " << typeid(s1).name() << endl;
cout << "decltype(s1) type : " << typeid(decltype(s1)).name() << endl;
return 0;
}
class A
{
public:
int i;
static int j;
void func1();
static void func2();
};
void A::func1()
{
this->j = 30;
A::j = 40;
cout << "this.i :" << this->i << endl;
}
void A::func2()
{
A::j = 50;
cout << "func2" << endl;
}
int A::j;
int test_class()
{
A::j = 10;
A a;
a.i = 1;
cout << "a.i :" << a.i << endl;
cout << "A::j :" << A::j << endl;
a.func1();
cout << "A::j :" << A::j << endl;
A::func2();
cout << "A::j :" << A::j << endl;
return 0;
}
class B
{
public:
void set_value();
private:
mutable int value;
};
void B::set_value()
{
value = 0;
value++;
cout << "value :" << value << endl;
}
int test_mutable()
{
B b;
b.set_value();
return 0;
}
constexpr int add_num(int a,int b)
{
return a+b;
}
int test_constexpr()
{
const int num = add_num(10,10);// const int num = 20;
cout << "num :" << num << endl;
return 0;
}
template <typename T>
T multiplicaty(T a,T b)
{
return a*b;
}
int test_template()
{
cout << "1*2 :" << multiplicaty(1,2) << endl;
cout << "1.1*2.2 :" << multiplicaty(1.1,2.2) << endl;
return 0;
}
int test_abnormal()
{
int m,n;
cout << "input dividend : ";
cin >> m;
cout << "input divisor : ";
cin >> n;
try
{
if(n == 0)
throw(1);
}
catch(int e)
{
cout << "divisor can't input 0,repeat input divisor : ";
cin >> n;
}
cout << "m/n : " << m/n << endl;
return 0;
}
int main()
{
cout << "------------------------------------" << endl;
bool_test();
cout << "------------------------------------" << endl;
test_cite();
cout << "------------------------------------" << endl;
test_enum();
cout << "------------------------------------" << endl;
test_nullptr();
cout << "------------------------------------" << endl;
test_static_assert();
cout << "------------------------------------" << endl;
mem_align();
cout << "------------------------------------" << endl;
test_typeid();
cout << "------------------------------------" << endl;
type_convert();
cout << "------------------------------------" << endl;
test_auto();
cout << "------------------------------------" << endl;
test_class();
cout << "------------------------------------" << endl;
test_mutable();
cout << "------------------------------------" << endl;
test_constexpr();
cout << "------------------------------------" << endl;
test_template();
cout << "------------------------------------" << endl;
test_abnormal();
cout << "------------------------------------" << endl;
return 0;
}
结果示例:
demo2:
namespace测试
目录结构:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.20) #最低版本要求
SET(CMAKE_CXX_COMPILER "g++") #设置g++编译器
PROJECT(namespace) #设置工程名
MESSAGE(STATUS "test namespace") #打印消息
ADD_EXECUTABLE(pro main.cpp namespace.cpp) #生成可执行文件
run.sh
#!/bin/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
namespace.hpp
#ifndef __NAMESPACE_HPP
#define __NAMESPACE_HPP
namespace
{
int num;
}
namespace n1
{
int num;
void printf_num(const int num);
}
namespace n2
{
int num;
namespace n3
{
int num;
void printf_num(const int num);
}
}
#endif
namespace.cpp
#include <iostream>
using namespace std;
namespace n1
{
int tmp;
void printf_num(const int num)
{
cout << "num :" << num << endl;
}
}
namespace n2
{
namespace n3
{
void printf_num(const int num)
{
cout << "num :" << num << endl;
}
}
}
main.cpp
#include <iostream>
#include "namespace.hpp"
using namespace std;
int main()
{
num = 1;
n1::num = 2;
cout << "num :" << num <<endl;
n1::printf_num(n1::num);
n2::num = 3;
cout << "num :" << n2::num << endl;
n2::n3::num = 4;
n2::n3::printf_num(n2::n3::num);
return 0;
}
结果示例:
demo3:
C++调用C
目录结构:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.20) #最低版本要求
SET(CMAKE_CXX_COMPILER "g++") #设置g++编译器
PROJECT(CPP_CALL_C) #设置工程名
MESSAGE(STATUS "cpp call c") #打印消息
ADD_EXECUTABLE(pro main.cpp clib.c) #生成可执行文件
run.sh
#!/bin/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
clib.h
#ifndef __CLIBC_H
#define __CLIBC_H
void func();
#endif
clib.c
#include <stdio.h>
#include "clib.h"
void func()
{
printf("c func\n");
return;
}
main.cpp
#ifdef __cplusplus
extern "C"
{
#endif
#include "clib.h"
#ifdef __cplusplus
}
#endif
int main()
{
func();
return 0;
}
结果示例:
demo4:
c调用c++
目录结构:
代码示例:
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.20) #最低版本要求
SET(CMAKE_CXX_COMPILER "g++") #设置g++编译器
PROJECT(CPP_CALL_C) #设置工程名
MESSAGE(STATUS "cpp call c") #打印消息
ADD_EXECUTABLE(pro main.c package_func.cpp cpplib.cpp) #生成可执行文件
run.sh
#!/bin/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./pro
cpplib.hpp
#ifndef __LIB_HPP
#define __LIB_HPP
void func();
#endif
cpplib.cpp
#include <iostream>
#include "cpplib.hpp"
using namespace std;
void func()
{
cout << "c++ func" << endl;
return;
}
package_func.hpp
#ifndef __PACKAGE_FUNC_HPP
#define __PACKAGE_FUNC_HPP
#ifdef __cplusplus
extern "C"
{
#endif
void package_func();
#ifdef __cplusplus
}
#endif
#endif
package_func.cpp
#include "cpplib.hpp"
#include "package_func.hpp"
void package_func()
{
func();
}
r
main.c
#include "package_func.hpp"
int main()
{
package_func();
return 0;
}
结果示例 :