语言/CPP {CPP知识汇总}

语言/CPP {CPP知识汇总}

关键字

friend

使用1: 全局有void F()这个函数的定义, 此时你在类里面写上friend void F();这个声明, 意味着 这个函数 可以访问当前类的私有;

使用2: 直接在类里面写friend void F(){ ...} 这个定义, 就相当于 你在全局定义了一个void F(){...}函数, 换句话说, 如果此时你在全局写void F(){..} 是会报错的!
. 因此 friend除了使用1这种功能, 他还有个功能: 在类内部 定义全局函数, 他不是成员函数;

@DELI;

写在类里面, 有2种用法:

class ST{
private:
	int data;
	
	//>> 不存在`private/public`的情况, 因为他不是该类的成员;
	friend void F1( ST);
	friend void F2( ST _a){ cout<< _a.data;}
};

void F1( ST _a){ cout<< _a.data;}

F1, F2是完全一样的 (都是全局函数, 不是类的成员函数 因此函数里没有this这个东西), F1这种用法比较常见, F2用法比较新颖 (他合并到一起了);

constexpr

constexpr对象;

如果一个类的构造函数 是constexpr函数, 则对象是literal字面类型;

该对象里的数据, 都必须是字面类型;

@DELI;

constexpr函数

构造函数, 成员函数, 全局函数, 都可以用constexpr来修饰;
constexpr int Func( int _x){ ...}

我猜他的本质是:
. 由于#define OP_( _x) _x * _x * _x这种方式, 如果你_x放的是个函数 那么他会执行3次, 当然你的本意是想让他执行1次;
为了实现此, 即执行一个op(x)操作 (当然可以用函数实现, 但毕竟函数调用有开销), 又能实现对_x函数 只调用1次, constexpr函数 我想大概如此 (即 虽然他是函数的样子, 但实际调用时 会优化成类似于宏定义, 而不是函数开销);

constexpr函数里, 只能使用: literal字面类型和constexpr函数;

constexpr int F( int _x){
    ST t(0); // ST是字面类型, 即他的构造函数是`constexpr`;
    ST2 * s = ?; // ST2不是字面类型, 但`T *`是指针 也是字面类型;
    for( int i = 0; i < _x; ++i) _x += i;
    return _x;
}

static

@DELI;

类的静态函数;

class ST{
	static int Func(){ ...}
};

这是错误的; 类的静态函数, 他的实现 不可以放到类声明里, 必须要单独拿出来;
换句话说, 他必须写成声明和实现分开的形式; 而且最重要的是: 声明时 要写static, 而实现时 不可以写static;

class ST{
	static int Func();
};

int ST::Func(){ ...};

以上是正确的; (如果你写成static int ST::Func(){ ...}就错了);

template

类的特化, 是完全不同的类;

template< int A> class ST{
public:
    int f;
    void F(){}
};
template<> class ST<0>{
public:
    int f0;
    void F0(){}
};
template<> class ST<1>{
public:
    int f1;
    void F1(){}
};

你现在有3个完全不同的类 (他们的数据/函数 都不同), 即ST< !={0,1}> ST<0> ST<1>;

你只要看到template<...> class ST{}; (即ST类名是单独的) 他就是, 即一切的特化 都是源自他的;
否则, 只要是template<...> class ST<?>{}; (即ST<?>类名后面有模板) 他就是特化版本;

@DELI;

不同的模板,是复制了多份不同的代码;

template< int _T> //< it is equivalent to `<class _T>` in here
void F(){
	static int a = 0;
	++ a;
	cout<< a;
}

F<1>(); F<2>();, finally, the output is 1 ; 2 1; 2 1;2;

But F<1>(); F<2>(); where there are two different a a a, so the output is 1 ; 1 ; 1;1; 1;1;

F< 1>();, you can consider it as there is a function void F_1()...; so, F<2>() means a function void F_2()...; they are totally different.

@DELI;

函数模板;

函数模板(不管是全局函数 还是类的函数) 与 类模板, 有一点不同;

模板类在实现时 必须写成template< class _T> ST<_T>::xxx, 即类名后面要带上<_T> (不仅用户使用时要这样, 连实现时也要带上);

可是, 模板函数 不管是声明还是实现时 必须写成如下形式:

template< class _T> void Func( _T);
template< class _T> void Func( _T){ ...}

不可以写成... Func< _T>( _T)...(只有是用户使用时 才可以写成Func<int>(...));

@DELI;

template< class _Type>模板参数 (分为2种: {类型, 整数常量}), 对于类型参数 是可以放你自定义的类型的;

template< class _Type>
void Func(){
	_Type obj; // MARK: @LOC_0;
	cout<< obj.data;
}

class ST{
public:	string data;
};

以上代码是正确的, 你调用Func< ST>()这是没问题的, 虽然LINK: @LOC_0编辑期间 无法知道_Type的类型 (IDE的提示 比如自动补全 肯定不知道obj里面有个data), 但这就是正确的代码 就是这样来使用的;

new

new T equals to new T[1]

new T[n] will allocate n items A1, A2, ..., An where Ai is a T, this operation return a pointer T * ptr;

new T[n][m] will allocate n items A1, A2, ..., An where Ai is a T[m], this operation return a pointer T (* ptr)[ m];

For generality, in new T[a][b][c]... only a could be variable, b, c, ... must be constant;

const

const int a = 123; //< must be initialized
const int b[3] = {1}; //< the same as `constexpr`

You should always remember that, a const/contexpr T must be initialized (otherwise, it is not const);
. Now you can found that, these three elements b[] are actually not the type const int, cuz the other two element is not initialized, (you can use is_same to check it);

type_id

const char * str = typeid( int).name() 获得该类型的底层名称;

@DELI;

typeid( int) = typeid( const int), but is_same< int, const int>::value would be false, so is_same is more stronger than typeid

decltype

const_cast

@Delimiter

int a = 1;
const int * p = &a;
int * pp = const_cast< int *>( p);
*pp = 2;

Now, a = *p = *pp = 2 and &a = p = pp;
That is, a Object (writable) and then given you a Const-Pointer of it, actually we can use this Const-Pointer to modify that object (cuz that object is writable);
. e.g., the const int * Head; in the template-algorithm of Linked-List graph, we can use const_cast to modify the private-data head, due to head itself is writable;

--

const int a = 1; //< the same as `constexpr`
const int * p = &a;
int * pp = const_cast< int *>( p);
*pp = 2;

Now, a = *&a = 1, *p = *pp = 2, &a = p = pp;
The reason is not figured out yet, or you can just consider that cuz a is const (itself is not writable);

--

const int a[3] = {1}; //< the same as `constexpr`

Now you can found that, these three element is actually not the type const int (cuz the other two element is not initialized), of course, these three element can be modified;

class/struct

*this;
在成员函数里, 有一个隐藏的变量: this: 表示执行当前函数的类对象的指针 (*this 即是其引用);

@DELI;

初始化列表构造临时对象;

class N{
    int a;
    string b;
};

The code ST a = { 123, "bb"} is wrong;
There is a special usage: ST a = { .a = 123, .b = "bb"};

@DELI;

constconstexpr成员变量;

class ST{
	ST( int _a)
			:
			a( _a){
	}
	const int a;
	static constexpr int A = 123;
};

constexpr variables in class must be static; so A is unique for ST (all objects of ST has the same unchangeable A; it must be initialized when declaring it which is also the unique way for assigning a constexpr variable; (the value of it is definite before the code-execution)

const variables is unique for a specific object of ST, not for ST; (ST t1 where t1.a = 1, while t2.a = 2 in another object), and the value of a const variable can be assigned by user with any custom value;

@DELI;

成员函数是friend友元的;

class ST{
	ST Get_deepCopy() const;
private:
	int data;
};
ST ST::Get_deepCopy() const{
	ST ret;
	ret.data = 123; //< 可以直接访问并修改其私有变量;
	return ret;
}

@DELI;

构造函数内的静态变量;

class ST{
public:
    ST(){
        static int a = 0;
        ++ a;
    }
};

ST a; ST b; finally, a a a equals 2 2 2;

@DELI;

强制单例类报警;

class ST{
	ST(){
		bool f = true;
		ASSERT_( f);
		f = false;
	}
};

But one exceptional case is that, if the class has Template ST<?>, then there can be multiple objects for ST, (i.e., a singleton-object of ST<1>, another for ST<2>, …);
If you wanna there must be one-object for ST not ST<?>, then you should forbid the Template for the class.

汇总

能使用this的唯一域 只有成員函數;
@IF(const成員函數): this, *this對應當前對象的const指針/引用;
@ELSE(非const成員函數): this, *this對應當前對象的非const指針/引用;

@DELI;

ST a = b, 其实他等价于 ST a( b) (也就是他调用的是*?构造函数*, 跟赋值运算符没有关系);

默认构造函数

拷贝构造函数

深拷贝, 即如果有指针 则需要开辟新空间

int * arr;

ST( const ST & _t){
	this->arr = new int[ Len];
	memcpy( this->arr, _t.arr, sizeof( int) * Len);
}

移动构造函数

浅拷贝, 即如果有指针 直接指向原内存即可;
. 因为所谓移动 即右值, 他表明 用户不再使用这个对象了, 你可以让新对象 免去申请内存的操作 直接就用原来的内存即可; 但要注意 要把原来对象的指针 置为nullptr 这样当他析构时 不会出错;

int * arr;

ST( ST && _t){
	this->arr = _t.arr;
	_t.arr = nullptr; // 别忘了这里, 否则当`_t`析构时 就出错了;
}

拷贝赋值运算符

void operator=( const ST & _t){
}

移动赋值运算符

void operator=( ST && _t){
}

数组

子数组的类型;

T A[ 3][ 4][ 5]

A的类型 即T[3][4][5];

A[?]的类型 为T[4][5];
. 也就是, sizeof( A[?]) = sizeof(T) * 4 * 5;

A[?][?]的类型 为T[5];
. 比如 sort( A[x][y], A[x][y] + 5) 就是让A[x][y][ ...]的这5个元素排序;

@DELI;

{数组元素的类型};

int A[10];, A[0]的类型 不是int 而是int &;
因此, 如果你要获取该数组元素的类型 必须是remove_reference_t< decltype( A[0])>;

@DELI;

{数组的类型, 数组指针的类型}

constexpr int N = ?, M = ?;
T a[ N], b[ N][ M];

auto t1 = a;
auto t2 = &a;
auto t3 = b;
auto t4 = &b;

a的类型 (即t1的类型) 为: T *;
&a的类型 (即t2的类型) 为: T (*)[N];
b的类型 (即t3的类型) 为: T (*)[M]; (注意是[M], 不是[N], 第一维度变成了指针);
&b的类型 (即t4的类型) 为: T (*)[N][M];

t1[ i] 等价于 a[ i] 等价于 (*t2)[ i];
t3[ i][ j] 等价于 b[ i][ j] 等价于 (*t4)[ i][ j];

指针

@DELI;

动态申请二维数组

If you need 2-Dimension Array [ m ] [ n ] [m][n] [m][n] where m, n are both variables, here are some devices:

+

T * * arr = new T * [m];
for( int i = 0; i < m; ++i){
	arr[ i] = new T[ n];
}

Note that, you have allocated T: n*m and T*: m, that is, you have additional T*: m, this is bad in Efficiency.

+ You need estimate the maximum of m, suppose it is M;

T (* arr)[ M] = new T[ n][ M];

This is good in Efficiency, but you always allocate T: n*M which are greater than n*m;

@DELI;

宏定义的参数可以含有标点符号;

#define F_( _x) cout<< _x
The code F_( "," << ',' << 1) is valid, which would becomes cout<< "," << ',' << 1

That is, @Par( _x) can contains any punctuation but excepts a Non-String Comma;
e.g., F_( 1, 2) is wrong, cuz there has one Non-String Comma that implies the macro F_ should own two parameters (it’s definition should be F_( a, b))

If we wanna using macro to replace this code auto wth = g.Head[0] and auto wth = g->Head[0] simultaneously.
A wrong macro is F_( _g) auto wth = _gHead[0] where _gHead would be viewed as a @Par, so there is a @Par named _gHead;
The correct device is F_( _g) auto wth = _g Head[0]

@DELI;

##字符拼接;

#define F_( _a, _b) int _a##_b = 213
Then F_( abc, 12) equals to int abc12 = 213

@DELI;

#字符串化;

#define F_( _a) #_a
The code auto ret = F_( a 1 * < ! hh abc 4); equals to const char * ret = "a 1 * < ! hh abc 4";

@DELI;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值