1 // CPPTEST.cpp : 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5
6 #include<map>
7 #include<vector>
8 #include<string>
9 #include<list>
10 #include<iostream>
11 #include <functional>
12 #include <fstream>
13 #include <regex>
14
15 using namespace std;
16
17 class CBase{
18 protected://注意,可以使用C#风格的定义时初始化
19 std::string name = "NoOne";
20 int age = -20;
21 int sex = 1;
22 public:
23 float *pData = new float[20]{1, 2, 3, 4, 5};
24 public:
25 virtual ~CBase(){//虚析构函数,防止内存泄漏:对基类指针调用delete时,会从子类一直析构到基类
26 cout << "~cbase" << endl;
27 }
28 };
29
30 //基类的私有成员不会被继承,这和C#完全一样
31 class CStudent : public CBase{
32 public:
33 std::map<int, std::string> _projs;
34 CStudent(){
35 pData = new float[20]{1, 2, 3, 4, 5};
36 }
37 public:
38 void SetName(const std::string& name){
39 CBase::name = name;//如果CBase.name定义为私有,这里就不可访问
40 this->name = name; //等价于上一行
41 }
42
43 const string& GetName(){
44 return this->name;
45 }
46
47 ~CStudent(){//若采用浅拷贝,析构函数被调用多次,pData被删除多次,程序崩溃
48 //规避方式:判断pData是否为空,非空才delete[] pData
49 //但在不知情的情况下使用pData仍然会出问题,因此浅拷贝导致的问题不可规避
50 cout << "~cstudent" << endl;
51 delete[] pData;
52 pData = NULL;
53 }
54 };
55
56 void TestSTL(){
57
58 auto mp = new std::map<int, std::string>();//c++11新风格 auto
59
60 mp->insert({ 10, ("h你好") });//c++11新风格,不用再使用std::pair()或std::make_pair()
61 mp->insert({ 20, "el" });
62 for (auto var : *mp)//c++11新风格for
63 {
64 std::cout << var.first << "," << var.second << "," << std::endl;
65 }
66 }
67
68 void TestClass(){
69 CBase* pbase = new CStudent();
70 auto pst = (CStudent*)pbase;
71 pst->SetName("xxxx");
72 auto name = pst->GetName();
73 delete pbase;
74 }
75
76 int TestAdd(int a, int b){
77 return a + b;
78 }
79 void TestStdFunc(std::function<int(int,int)> fun, int a, int b){
80 auto ret = fun(a, b);
81 }
82
83 typedef int(*TestAddPtr)(int, int);
84
85 void TestPCall(TestAddPtr func, int a, int b){
86 auto ret = func(a, b);
87 }
88
89 struct Vertex{
90 bool isgood;
91 float x, y, z;
92 double dx;
93 bool bx;
94 int ix;
95 bool by;
96 };
97 void TestFile(){
98 int szChar = sizeof(char);
99 ofstream ofs;
100 ofs.open("f:/test.txt");
101 ofs << "hello " << 10 << " world " << 20 << endl;
102
103 ofs.flush();
104 ofs.close();
105
106 ifstream ifs;
107 ifs.open("f:/test.txt");
108 string str1, str2;
109 int num1, num2;
110
111 ifs >> str1 >> num1 >> str2 >> num2;
112
113 //错误示例:二进制读写,使用std::<<或>>进行的还是ASCII码的读写
114 ofstream ofsb;
115 ofsb.open("f:/testb", ios::binary);
116 ofsb << "hellob" << 1022;
117
118 ofsb.flush();
119 ofsb.close();
120 ifstream ifsb;
121
122 string sx;
123 int nx;
124 ifsb.open("f:/testb", ios::binary);
125 ifsb >> sx >> nx;
126 ifsb.close();
127
128 //正确做法
129 sx = "binary";
130 nx = 978;
131 ofsb.open("f:/testbx", ios::binary);
132 ofsb.write(sx.c_str(), sx.length()*sizeof(char)+1);
133 ofsb.write((const char*)&(nx), sizeof(int));
134 ofsb.flush();
135 ofsb.close();
136
137 char sxr[32];
138 int nxr;
139 ifsb.open("f:///testbx", ios::binary);//注意这里的"///"不管有多少个/都等同于一个
140 ifsb.read(sxr, sx.length()+1);
141 ifsb.read((char*)&nxr, 4);
142
143 //数据转换的更通用方式
144 Vertex vt;
145 vt.bx = true;
146 vt.isgood = false;
147 vt.x = 12;
148 vt.y = 13;
149 vt.z = 14;
150 vt.dx = 3.9;
151 vt.by = 0;
152
153 ofstream ofsbx;
154 ofsbx.clear();
155 ofsbx.open("f:/testbyx2", ios::binary);
156 ofsbx.write((const char*)&(vt), sizeof(Vertex));
157 ofsbx.flush();
158 ofsbx.close();
159
160 ifstream ifsbx;
161 Vertex vrt;
162 ifsbx.clear();
163 ifsbx.open("f:/testbyx2", ios::binary);
164 ifsbx.read((char*)&vrt, sizeof(Vertex));
165
166 string s1 = "hello";
167 string s2 = "wrold";
168 s1 = s1 + s2;
169 auto s3 = s1.substr(1, 2);
170 }
171
172 //实现较为高效的字符串分割,限制是分割符只能是一个字符,不能是一个串
173 std::list<string> TestStrSplit(string s, char sep){
174 std::list<string> lst;
175 for (int i = 0, j = 0; i < s.length(); ++i){
176 if (s[i] == sep){
177 lst.push_back(s.substr(j, i - j));
178 j = i + 1;
179 }
180 }
181
182 //注意临时对象作为返回值了,一般情况下这是错误的用法,栈上的临时对象出了函数域后会被释放
183 //但这里STL容器内部重载了=运算符,作了值拷贝就没问题了
184 return lst;
185 }
186 void TestString(){
187
188 //g正则表达式实现字符串分割
189 string s1 = "a;b;c;dddd;ef;";
190 string s2 = "a123b2673cdd4444a";
191 std::regex re("(d+)");
192 std::smatch mtch;
193
194 //这个做法效率挺低且浪费内存,产生了很多中间字符串
195 while (std::regex_search(s2, mtch, re, std::regex_constants::match_default)){
196 cout << mtch.str() << endl;
197 s2 = mtch.suffix();
198 }
199
200 //这个函数效率要高多了
201 auto lst = TestStrSplit(s1, ';');
202
203 }
204
205 //返回栈上的临时对象测试
206 CStudent TestTempObjRet(){
207 CStudent ost; //临时对象
208 return ost; //调用对象的拷贝构造函数
209 }//出了栈后ost被释放,析构函数调用,同时成员对象被析构CStudent.name="",但内置类型仍保持原值
210
211 //通过测试可知,将栈上对象作为函数返回值使用一般是没有问题的,但浅COPY时两个对象中的指针指向同一份
212 //内存,当一个对象被删除时,另一个对象中的指针就指向非法位置了,成了野指针
213 void TestObjConstructorAndDestructor(){
214 CStudent ostx;
215 ostx = TestTempObjRet(); //调用拷贝构造函数(与上面对应)
216 auto name = ostx.GetName();
217 auto px = ostx.pData;
218 }
219
220 void TestRRef(){
221
222 }
223
224 //可以使用随机访问(数组下标)说明vector在内存中是连续存放的
225 //这样,vector在需要扩充容量时就需要将原来内存删除,再申请一块新内存
226 //但这并不一定,因为内存申请时若用realloc则有可能会在原内存后面增加(原理)
227 void TestVector(){
228 std::vector<string> sv{ "hello", "world" };
229 sv[0];
230 sv[1];
231
232 sv.reserve(20); //旧的内容被清除
233 int n = sv.capacity(); //20
234 sv.push_back("a");
235 sv.push_back("b");
236 sv.clear(); //旧的内容被清除
237 n = sv.capacity(); //20
238
239 sv.shrink_to_fit(); //内存释放
240 n = sv.capacity(); //0
241
242 }
243
244 struct CTA{
245 private:
246 virtual void Test(){
247 cout << "cta" << endl;
248 }
249
250 };
251
252 class CCTA : CTA{//类和结构体可以相互继承
253 public:
254 int _id;
255 void Test() const{
256 cout << "ccta-test" << endl;
257 }
258 };
259
260 //C++中字符串有常量和变量之分,字符串遇到 则结束
261 //C#中只有常量字符串,字符串遇到 不结束,视其为正常字符
262 void TestStr(){
263 char* ps = "hello";//字符串常量,不可修改其内容
264 ps[0] = 'd'; //运行出错
265
266 char arr[] = "hello"; //字符串变量
267 char* par = arr;
268 arr[0] = 'd'; //ok
269 }
270
271 //C++中指针字符串与数组字符串都是自动以0结尾的
272 void TestMemcpy(){
273
274 char dest[18];
275 char src[] = "hell"; //以0结尾,长度为5,若强制声明为 char src[4] = "hell"则编译报错
276 char* psrc = "hell"; //以0结尾,长度为5,但测试长度strlen(psrc)为4,因为它没算尾0
277
278 for (int i = 0; i < 10; ++i){
279
280 }
281 for (int i = 0, ch; (ch = psrc[i++]) != 0;){
282 //这里发现字符串尾0后有许多个0,不知道原因
283
284 }
285 auto len = strlen(psrc); //4,测试长度,并没字符串的真实长度(内存中真实串),因为它有尾0
286 int len2 = strlen(src); //5,字符串实际长度(内存中存储的字符串)
287 int st = sizeof(src); //5,数组大小
288 memcpy(dest, psrc, strlen(psrc)+1);
289 }
290 template<typename T1, class T2> class MyVector{
291 std::vector<int> _lst;
292
293 public:
294
295 void Test2();
296 };
297
298 template<class T1, class T2> void MyVector<T1, T2>::Test2(){
299
300 }
301 int _tmain(int argc, _TCHAR* argv[])
302 {
303 TestMemcpy();
304 // auto pox = new CCTA();
305 // pox->Test();
306 //
307 // MyVector<int, float> _v;
308 //_v.Test<float>();
309 //TestSTL();
310 //TestClass();
311 //TestStdFunc(TestAdd, 10, 20);
312 //TestPCall(TestAdd, 10, 23);
313 //TestFile();
314 //TestString();
315 //TestObjConstructorAndDestructor();
316 //TestVector();
317
318
319
320 return 0;
321 }