c++/c学习笔记-基础(3)

  1. 参数传递

当实参的值被拷贝给形参时,形参与实参是两个相互独立的对象。我们说这样的实参被值传递。本质上说,都为值传递。所以若对于一个大的自定义对象,如此传递的方式是可取的,代价有些大,所以传入参数,特别是传入个人的一些大的类型对象时,应该使用指针或引用。若在函数中不牵扯到值的改变。则应尽可能使用const。另,若仅是指针或引用,则不能传入一个字面值(一方面不能给字面值取地址,二是把一个字面值赋给非常量引用肯定会出错)。从这个角度也是可以理解指针和引用在期间的作用的。其本质是在参数列表处做了一次同值运算而已。所以,我们不可以把一个const类型赋给一个非const类型。

对于函数顶层const,在函数的形参会被忽略掉,所以,对于一个具有同名,而参数列表若只有const 差别时,视为重定义,会报错的!如:

void reset(int&);//方法1
void reset(int*);//方法2
int main() {
	int i=0;
	const int ci =i;
	unsigned ctr =0;
	reset(&i);
	//reset(&ci); &ci为const int*,而形参为int*,故不可赋值
	reset(i); //调用 方法1
	//reset(ci); //错误,不能把普通引用绑定到一个const 对象上
	//reset(34); 不能把普通应用绑定到一个字面值上,这个需注意,
	//reset(ctr); 类型不匹配
	return 0;
}
//对于函数顶层const,在函数的形参会被忽略掉,所以,对于一个具有同名,而参数列表若只有const 差别时,编译器不会识别区分,会以相同认为重定会报错的!如<pre name="code" class="cpp">string fcn(const int i)
{
      return "cosnt int";
 }
string fcn(int i)
{
    return "int";
}
// 上面fcn属于重定义
 void lookup(int*)
{ cout<<"int*";
}

void lookup(int* const)
{
    cout<<"int* const";
}
//上面lookup属于重定义
 
  

但其对于底层const并无此作用

#include <iostream>

using namespace std;


void fcn(const int& i)
{
      cout<< "cosnt int&"<<endl;
 }
void fcn(int& i)
{
    cout<<"int&"<<endl;
}
void lookup(int*)
{ cout<<"int*"<<endl;
}

void lookup(const int* )
{
	cout<<"int* const"<<endl;
}

int main() {
int s =3;
const int cs =s;
	lookup(&s);
	lookup(&cs);
	int& e =s;
	const int& ce =e;
	fcn(e);
	fcn(ce);
	return 0;
}


2.数组形参

1.数组形参,其表示的含义是相同的

void print(const int*);
void print(const int[]);
void print(const int[10]);
2.数组引用形参,数组指针形参
void print(int (&arr)[10]);//arr是具有10个整数数组的引用
void print( int &arr[10]);//arr声明成引用的数组
void print(int (*arr)[10]);//指向10个整数的数组的指针
void print(int *arr[10]) ;//10个指针构成的数组

3.含有可变形参的函数

老式的c可用...,但c11中可以使用initializer_list<T>如:

#include <iostream>

using namespace std;
void ini_example(initializer_list<string> list){
	for(auto i : list){
		cout<< i <<endl;
	}
}
int main() {
	ini_example({"nihao","zaijian","women","huajd"});//其传入应使用{}包括。

	return 0;
}
注,省略符形应该仅仅用于c和c++通用的类型。但需要注意的是,大多数类类型的对象在传递给省略符形参时都无法正确拷贝。

3.返回值

  1. 不要返回局部对象的引用或指针。
  2. 函数可以返回花括号包围的值的列表、
  3. 返回类型可以使用decltype,也可以使用auto结合尾置类型
    string a;
    auto return_func(void) ->string
    {
        return "return_func";
    }
    decltype(a) return_func_dec(void)
    {
        return "retrun_func_dec";
    }
    
    int main() {
        cout<<return_func()<<endl<<return_func_dec();
    
        return 0;
    }

4.constexpr函数

constexpr函数是指用于常量表达式,即可以在编译期就已经计算出的值。所以可将其用于数组大小的声明等地方。(注,返回const的 函数不具有此功能,虽const 变量可以)。其要求是仅有一条语句,且只能是return语句,其返回值是和所有形参的类型都是字面值类型。

#include <iostream>

using namespace std;

constexpr int new_sz(int s){
	return 43+s;
}
int main() {
	int a=4;
	int array[new_sz(2)]={0};
	//int array1[new_sz(a)]={0}; 此编译不过,由于传入的参数只能是字面值
	for(auto i : array){
		cout << i <<" ";
	}
	return 0;
}

5.有关调试的问题

  1. 断言aseert。断言是 一种编程手段,可以通过NDEBUG来开闭。
  2. 静态断言static_assert,相对断言assert只有在程序运行时才起作用,静态断言,可以在编译期便排除,问题在于,调试信息可能难以判断但我们可以通过参数业实现。但static_assert可以追加第二参数,表明断言信息。
    #include <iostream>
    #include <cassert>
    using namespace std;
    static_assert(sizeof(int)!=8,"int is not 8"); // 这是可以,尽量将其独立于函数。好定位。
    
     int new_sz(const int s){
    	 const int a =s>0;
    
    //	static_assert(a,"value must > 0"); 由于静态断言,使用了变量 会报错的!assert 是可以使用变量的。当然其断言也将推到运行期
    	return a;
    }
    int main() {
    	cout << new_sz(2);
    	return 0;
    }

  3. __func__        __FILE__     __TIME__   __DATE__   __LINE__ 这些,在c11,其甚至可以用在类的列表初始化值
    #include <iostream>
    #include <cassert>
    using namespace std;
    struct s{
    	string name;
    	int line;
    	string time;
    	string file;
    	string date;
    	s():name(__func__),line(__LINE__),time(__TIME__),file(__FILE__),date(__DATE__){
    
    	}
    };
    int main() {
    	 s a;
    	 cout << a.name<<endl<<a.line<<endl<<a.time<<endl<<a.file<<endl<<a.date;
    	return 0;
    }

6.函数匹配

  1. 精确匹配
    • 实参类型与形参类型相同
    • 实参从数组类型或函数类型转换成对应的指针类型
    • 顶层const的删除或添加
  2. 通过const 转换实现的匹配(底层const,主要集中在引用,指针的底层const)
  3. 通过类型提升实现匹配(数值类型)
  4. 通过算术类型转换(有符号数转为无符号数等,可能产生)或指针转换(void*,bool,)
  5. 通过类类型转换实现的匹配

7.函数指针

  1. 重载函数的指针,上下文必须清晰给出选用的函数。
  2. 在参数中,函数类型的形参与数组相同与其对应的指针参数等价
    void func( bool pf(const string& a));
    void func(bool (*pf)(const string& a));
  3. 函数指针和函数类型是两个不同的概念。函数不能返回函数类型,只能返回一个函数指针。
    using f = int(int*,int); //f 是一个函数类型
    using fp= int(*)(int*,int); //fp 是一个函数指针
    //f f1(int); //错误的,函数f1不能返回一个函数指针。
    fp f2(int);//正确的 返回一个函数指针
    f* f3(int);//正确的
  4. 返回函数指针一般最后使用decltyp或尾置的方式来解决。




 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值