时间:2020年07月09日 | 作者 : aaronyang | 分类 : C++ | 浏览: 1010次 | 评论 0 人
发现C++的函数,只能定义在被调用的上方,不然找不到,即时在下面定义都不行。
这样可以的。
bb方法在下面就不行
只列出我觉得和C#不一样的地方
例如它的 局部静态对象
size_t count_calls() { static size_t ctr = 0; return ++ctr; } //int id = 122; int main() { for (size_t i = 0; i < 10; i++) { cout << count_calls() << endl; } return 0; }
输出1到10
C#函数内不允许static的
这玩意有点类似C#的 委托声明
也像C#接口的定义的方法
void print(int a,string b);
上面声明一下,然后就可以调用,具体bb()方法的内容,可以定义在被调用的 代码 之下了。
允许我们把程序分割到几个文件中去,每个文件独立编译
具体百度。
因为这个敲命令行的,我还不太会。
如果我们修改了其中一个源文件,那么只需重新编译那个改动了的文件。大多数编译器提供了分离式编译每个文件的机制,这一过程通常会产生一个后缀名是 .obj(Windows) 或 .o(UNIX)的文件,后缀名的含义是该文件包含对象代码。
$ CC -c factMain.cc #generates factMain.o
$ CC -c fact.cc #generates fact.o
$ CC factMain.o fact.o # generates factMain.exe or a.out
$ CC factMain.o fact.o -o main # generates main or main.exe
类似C#的ref
void resetRef(int &i) { i = 0; }
比如比较字符串谁更短
bool IsShorter(const string& s1, const string& s2) { return s1.size() < s2.size(); }
当函数无须修改引用形参的值时最好使用常量引用。
你可以新建新的数据类型个,2个字段,还有简洁的用法,就是类似C#的out用法,我们直接传引用参数,就是上面讲的,形参前面加一个&符号
size_t find(const string &s,char c,size_t &sizet){
这里对sizet赋值就好了。
}
C#也有Tuple类型,可以,js现在也有了。
C#有方法重载,对于C++的参数,如果被const修饰了,例如下面不算重载,会错误的
void fcn(const int i)
void fcn(int i)
尽量使用常量引用
string::size_type find_char(string& s, char c, string::size_type& occurs) {
}
第一个形参的类型,应该是const string&
下面调用讲在编译时发生错误
还有二次引用
上面只读的,传给 普通的string& s,肯定报错
换成这种就好了
在C#直接参数,写个List<T> p1,这种作为方法参数就行了
C++中,要传指针,数组不允许拷贝的
我们使用收尾元素的指针
void print(const int* beg, const int* end) { while (beg != end) { cout << *beg++ << endl; } } int main() { int aa[] = { 1,2,3,4,5 }; print(begin(aa), end(aa));
还有一种,感觉类似C#
通用也可以加const修饰,当不需要写的时候
数组的形参引用
void print(int (&array)[10]){
for(auto ele:array){
cout<<ele<<endl;
}
}
缺点,传递的数组要 10个长度的。
AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢
目前我们的main都是空的
int main(int argc, char **argv)//也可以写成char *argv[],argc是个数,argv每个选项是一个字符串
注意:argv[0]是命令,不是命令行选项
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
printf("argc:%d\n",argc);
for(int i = 0;i < argc; ++i)
printf("%s\n",argv[i]);
system("pause");
}
argc包括命令行选项的个数
argv包含argc个C风格字符串,代表了由空格分隔的命令选项。例如,对于如下命令行:prog -d -o ofile data0,
argc被设置为5,且argv被设置为下列C风格字符串:
argv[0] = "prog";
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = 0;
argv[0]总是被设置为当前正在被调用的命令(程序运行生成的exe文件名,不包括扩展名)
从索引1到argc的值,这里是5,所以1到5的值,1表示被传递给命令的实际选项。
命令行编译程序的具体步骤:
先编译运行上述代码,在将生成的exe文件拷贝至C盘目录下(自己设置)。然后打开命令提示符:
输入cd C:\切换工作目录至C盘目录。
再输入prog h wh wh。
program_name [-d] [-h] [-v] [-o output_file] [-l limit_value] file_name [file_name [file_name [...]]]。
//C/C++处理main()函数命令行 #include <iostream> #include <vector> #include <string> #include <ctype.h>//调用atoi函数 using namespace std; const char* const prog_name = "prog"; const char* const prog_version = "version 1.0 (2020/7/10)"; //退出函数 inline void usage(int exit_value = 0){ cerr<<prog_name<<" usage!"<<endl; exit(exit_value); } int main(int argc,char* argv[]){ //声明用于记录用户指定选项的变量 bool debug_on = false; bool ofile_on = false; bool limit_on = false; string ofile_name;//记录出现的输出文件名 int limit = -1;//限制值 vector <string> file_names;//记录文件名 cout<<"argc:"<<argc<<endl; for(int i = 1;i < argc; ++i){//读取argv中的每个选项 //输出第i+1个参量 cout<<"argv["<<i<<"]:"<<argv[i]<<endl; char *pchar = argv[i]; switch(pchar[0]){//确定选项类型:-h,-d,-v,-l,-o;或者其他 case '-':{ cout<<"case \'-\' found"<<endl; switch(pchar[1]){//确定用户指定的选项:h,d,v,l,o case 'd'://处理调试: cout<<"-d found:debugging turned on!"<<endl; debug_on = true; break; case 'v'://处理版本请求 cout<<"-v found:version info displayed!"<<endl; cout<<prog_name<<":"<<prog_version<<endl; return 0; case 'h'://处理帮助 cout<<"-h found:help info!"<<endl; usage(); case 'o'://处理输出文件 cout<<"-o found:output file!"<<endl; ofile_on = true; break; case 'l'://处理限制量 cout<<"-l found:resorce limit!"<<endl; limit_on = true; break; default://无法识别的选项 cerr<<prog_name<<":error:unrecognition option -:"<<pchar<<endl; usage(-1); } break; } default://不以'-'开头,是文件名 if(ofile_on){//输出文件名 cout<<"file name:"<<pchar<<endl; ofile_name = pchar; ofile_on = false;//复位 } else if(limit_on){//限制值 limit_on = false; limit = atoi(pchar); if(limit<0){ cerr<<prog_name<<":error:negative value for limit!"<<endl; usage(-2); } } else{//文件名 file_names.push_back(pchar); } break; } } if(file_names.empty()){ cerr<<prog_name<<":error:no file for processing!"<<endl; usage(3); } else{ cout<<(file_names.size() == 1 ? "File":"Files")<< " to be processed are the followed:"<<endl; for(int i = 0;i < file_names.size();++i){ cout<<file_names[i]<<"\t"<<endl; } } if(limit != -1){ cout<<"user-specified limit:"<<limit<<endl; } if(!ofile_name.empty()){ cout<<"user-specified ofile:"<<ofile_name<<endl; } }
initializer_list<T>
跟vector差不多,这个语法类似C#的方法参数的params修饰符号
就是不知道有多少个参数
用法
initalizer_list<T> lst;
initalizer_list<T> lst{a,b,c,...};
lst2(lst)拷贝或赋值一个initializer_list对象不会拷贝列表的元素;拷贝后,原始列表和副本共享元素
lst.size();
lst.begin()
lst.end()
void error_msg(initializer_list<string> li) { for (auto begin = li.begin (); begin !=li.end(); ++begin) { cout << *begin << endl; } } int main() { string expect = "hellay"; string actual = "helloay"; if (expect != actual) { error_msg({"funcAy",expect,actual}); } else { error_msg({ "funcAb","一致的" }); }
当然error_msg的list参数前面还是可以加其他参数的
C++还有省略符形参
void foo ( parm_list , ...);
void foo ( ... );
#include <cstdarg> void ArgFunc(const char* str, ...) { va_list ap; int n = 3; char* s = NULL; int d = 0; double f = 0.0; va_start(ap, str); // 注意!这里第二个参数是本函数的第一个形参 s = va_arg(ap, char*); d = va_arg(ap, int); f = va_arg(ap, double); // 浮点最好用double类型,而不要用float类型;否则数据会有问题 va_end(ap); printf("%s is %s %d, %f", str, s, d, f); }
使用时候
ArgFunc("The answer", "Hello", 345, 788.234);
省略符形参是为了便于C++程序访问某些特殊的C代码而设置的,这些代码使用了名为varargs的C标准库功能。你的C编译器文档会描述如何使用varargs
方法返回值,有的是复杂的指针,那就在方法名前面加& 或者*号修饰
或者有的用const修饰的
函数完成后,它所占用的存储空间也随之被释放掉。因此,函数终止意味着局部变量的引用将指向不再有效的内存区域。
char& get_val(string &str,string::size_type ix) { return str[ix]; }
返回是对一个字符的引用。
还可以这样写
vector的返回,可以花括号,这个有点像C#的Tuple了
main函数不能调用自己的。返回0表示成功,其他是失败
一般返回数组的指针,或者引用
数组的名字太长了,可以如下简化,arrT是int[10]的别名
func(int i)表示调用函数时,需要一个int类型的参数;
(*func(int i))表示对调用func的结果执行解引用的操作;
(*func(int i))[10]表示解引用之后得到一个维度为10的数组;
int (*func(int i))[10]表示数组的数据类型为int;
auto func(int i) ->int(*)[10];
返回一个指针,该指针指向含有10个整数的数组。
具体更多,参考
//返回指向数组的指针 auto func1(int arr[][3], int n) -> int(*)[3] { return &arr[n]; }
要不然你得
int (* func1(int arr[][3], int n))[3] { return &arr[n]; }
还有更复杂的
//函数接受一个指向func1函数的指针的参数,返回指向func2的函数的指针; auto func3(int(*(*ptf)(int arr[][3], int n))[3]) -> int (*(*(*)())(int arr[][3], int n))[3]{ ... }
你也可以使用decltype()
例如
int odd[] = { 1,3,5,7,9 }; int even[] = { 0,2,4,6,8 }; decltype(odd)* arrptr(int i) { return (i % 2) ? &odd : &even; }
方法返回值和名字一样,方法参数列表不一样。
const修饰的参数的 方法,参数是指针或者引用时, const在前面算,在后不算。
C++的方法内,可以定义方法
会覆盖外面的同名的方法域
方法的参数也可以默认值,和C#一样
方法前面返回值 类型 前面加一个 inline
inline const string& shortString(const string &s1,const string &s2){
}
方法前面,或者 字段前面加constexpr,就可以运行时候,计算得到个结果,并把值替换掉 原来位置的代码。
和其他函数一样,内联函数和constexpr函数可以在程序中多次定义。
assert定义在cassert头文件中
预处理宏
assert(word.size()>threshold)
NDEBUG预处理变量
assert依赖一个名为NDEBUG的预处理变量的状态。定义了,assert什么也不做。默认情况没有定义的,运行时检查
具体百度吧
#define NDEBUG
#ifndef NDEBUG
......
#endif
__func__函数的名字
__LINE__当前行号
__FILE__存放文件名
__TIME__
__DATE__
实战下:
新建test2.cpp,从项目中移除test1.cpp
#include<iostream> #include<string> #include<vector> #include<cassert> using namespace std; void read_vi(vector<int>::const_iterator iterator_begin, vector<int>::const_iterator iterator_end) { #ifndef NDEBUG cerr << iterator_end - iterator_begin << __func__ << " " << __FILE__ << " " << __LINE__ << " " << __TIME__ << " " << __DATE__ << endl; #endif // !NDEBUG if (iterator_begin != iterator_end) { cout << *iterator_begin << " "; return read_vi(++iterator_begin, iterator_end); } else { cout << endl; return; } } int main() { vector<int> v{ 1,2,3,4,5 }; read_vi(v.begin(), v.end()); system("pause"); return 0; }
如果没有定义NDEBUG
则执行
AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢
代码
下面的main就是 遍历vector 列表
接下来,打开属性
点击确定
运行时候,由于定义了,所以不会进入那段代码了
指向是函数而非对象
定义一个函数
bool lengthCompare(const string &,const string &)
定义个函数指针
bool (*pf)(const string &,const string &)
声明了以后
这个就和C#的委托很像了
调用
也可以直接
bool bb3 = lengthCompare("hello1", "hello2");
pf=0的话或者pf=nullptr, 意思是,不指向任何函数
当函数指针 指向的 函数有重载
需要
bool (*pf)(const string &,const string &) =lengthCompare
就是返回类型,形参列表要一致
函数指针可以当做 方法的参数,把函数传入,会自动转换为指针
void A1(const string &s1, bool (*pf)(const string&, const string&)) { } void A2(const string& s1, bool lengthCompare(const string&, const string&)) { }
这样方法的参数 名字类型好长
typedef bool Func(const string&, const string&); typedef decltype(lengthCompare) Func2;//等价的类型 typedef bool (*FuncP)(const string&, const string&); typedef decltype(lengthCompare) *FuncP2;//等价的类型
定义类型后,使用
void UserBigger(const string&, const string&, Func); void UserBigger(const string&, const string&, FuncP2);
using F = int(int*, int); //p是函数类型,不是指针
using pF = int(*)(int*, int);//pf是指针类型
根据需要返回一个函数指针,使用auto和decltype简写
输入a,返回sum1,输入2返回sum2
string::size_type sum1(const string&, const string&); string::size_type sum2(const string&, const string&); decltype(sum1)* getSum(const string&); string::size_type sum1(const string& str1, const string& str2) { return 1; } string::size_type sum2(const string& str1, const string& str2) { return 2; } decltype(sum1)* getSum(const string& str1) { if (str1 == "a") { return sum1; } else { return sum2; } }
调用如下:
cout << getSum("a")("a1","b1") << endl;
输出1,换其他,返回sum2,然后传参,返回2
AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢
int demo(int* p, int a) { return 12; } int (*ff(int x))(int*, int) { cout << x << endl; return demo; } auto ff2(int x) -> int(*)(int*, int) { cout << "ay:"<<x << endl; return demo; } int main() { int a = 8; cout << ff2(2)(&a, a) << endl;
使用别名简写
int demo(int* p, int a) { return 12; } int (*ff(int x))(int*, int) { cout << x << endl; return demo; } auto ff2(int x) -> int(*)(int*, int) { cout << "ay:" << x << endl; return demo; } using PF2 = int(*)(int*, int);//pf2是指针类型 PF2 ff3(int x) { cout << "ay3:" << x << endl; return demo; }
交换位置
#include<iostream> using namespace std; void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int main() { int x, y; cin >> x >> y; cout << x << y << endl; swap(x, y); cout << x << y << endl; system("pause"); return 0; }
发现
&号可写可不写的。
感觉写正规点
void swap(int &x, int &y) { int temp = x; x = y; y = temp; }
AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢
加减乘除,放入vector函数指针类型的列表里
#include<iostream> #include<string> #include<vector> using namespace std; int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int multi(int a, int b) { return a * b; } int divide(int a, int b) { return a / b; } int main() { vector<int(*)(int, int)> vf{ add,sub,multi,divide }; for (const auto e : vf) cout << e(4, 2) << endl; system("pause"); return 0; }
推荐您阅读更多有关于“C++,”的文章
抖音:wpfui 工作wpf,目前主maui
招聘合肥一枚WPF工程师,跟我一个开发组,10-15K,欢迎打扰
目前在合肥市企迈科技就职
AYUI8全源码 Github地址:前往获取
杨洋(AaronYang简称AY,安徽六安人)和AY交流
高中学历,2010年开始web开发,2015年1月17日开始学习WPF
声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费
不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo
查看捐赠AYUI7.X MVC教程 更新如下:
第一课 第二课 程序加密教程
额 本文暂时没人评论 来添加一个吧
发表评论