多态&指针访问虚函数&不能被继承的类&快速排序&N皇后问题&插入排序&堆排序&merge归并排序&栈上生成对象&两个栈实现一个队列
来源:互联网 发布:mfc编程实例 2008 编辑:程序博客网 时间:2024/06/13 00:10
多态
/* 1. 要想实现覆盖(重写)父类必须声明为virtual,子类可以不声明为virtual.-->FunB() 2. 派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外) 3. 基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。 4. 只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。 5. 如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。 6. 构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容 易混淆 7. 不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会 出现未定义的行为。 8. 最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构 函数名称不一样,但是构成覆盖,这里编译器做了特殊处理) 9. 虚表是所有类对象实例共用的*/#include<iostream>using namespace std;class CBase{public: virtual void FunA(int a) { cout << "CBase::FunA()" << endl; } void FunB(int a) { cout << "CBase::FunB()" << endl; } virtual void FunC(int a1) { cout << "CBase::FunC()" << endl; } virtual void FunD(int a) { cout << "CBase::FunD()" << endl; }};class CDerived :public CBase{public: virtual void FunA(int a) { cout << "CDerived::FunA()" << endl; } virtual void FunB(int a) { cout << "CDerived::FunB()" << endl; } void FunC(int a1) { cout << "CDerived::FunC()" << endl; } virtual void FunD(int a1, int a2) { cout << "CDerived::FunD()" << endl; }};int main(){ CBase* pBase = new CDerived; pBase->FunA(0); //CDerived::FunA() pBase->FunB(0);//CBase::FunB() pBase->FunC(0);//CDerived::FunC() pBase->FunD(0);//CBase::FunD()// pBase->FunD(0,0);//编译报错error C2660: “CBase::FunD”: 函数不接受 2 个参数 system("pause"); return 0;}/* 1. 覆盖: 1.不同的作用域(分别位于基类和派生类中) 2.函数名称完全相同 3.参数列表完全相同 4.基类函数必须是虚函数 5.返回值类型相同(协变除外) 2. 重载: 1.具有相同的作用域 2.函数名字相同 3.参数类型顺序或数目不同(包括const和非const参数) 4.virtual关键字可有可无 3. 隐藏: 1.派生类的函数与基类的函数同名,但是参数列表有所差异。 此时不论有没有virtual关键字,基类的函数在派生类中都将被隐藏。 2.派生类的函数与基类的函数同名,参数列表也相同,但是基类函数没有 virtual关键字。基类的函数也会被隐藏。 */
指针访问类里面的虚函数
#include<iostream>using namespace std;class A{public: virtual void FunA() { cout << "我是A的FunA" << endl; } virtual void FunB() { cout << "我是A的FunB" << endl; }};class B :public A{public: virtual void FunA() { cout << "我是B的A" << endl; } virtual void FunB() { cout << "我是B的B" << endl; } virtual void FunC() { cout << "我是B的FunC" << endl; } virtual void FunD() { cout << "我是B的FunD" << endl; }};/*定义一个有10个指针的数组tmp,该指针是指向一个整形数: int *tmp[10];一个指向有10个整形数数组的指针tmp: int (*tmp)[10];一个指向函数的指针,该函数有一个整型参数并返回一个整型数:int (*fun)(int);一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数: int(*fun[10])(int);*/typedef void(*Fun)(void);int main(){ B b; A a; Fun pFun[3]; for (int i = 0; i < 4; i++) { pFun[i] = (Fun)*((int *)*(int *)&b + i); /* *(int*)&b:取到虚函数表的首地址 *(int *)*(int *)&b:取到第一个函数的函数指针 */ pFun[i](); } /* 我是B的A 我是B的B 我是B的FunC 我是B的FunD 请按任意键继续. . . */ system("pause");}
设计一个不能被继承的类
/* 设计一个不能被继承的类 1. 利用友元类可以访问类里所有成员的特性 2. 利用虚基类的构造函数需要由最终的子类调用完成构造的特性*/#include<iostream>using namespace std;class Grand{ friend class Parent;private: Grand() {} ~Grand() {}};class Parent:virtual public Grand{public: Parent() {} ~Parent() {}};/* 设计一个不能被继承的类.cpp(30): error C2248: “Grand::Grand”: 无法访问 private 成员(在“Grand”类中声明) 设计一个不能被继承的类.cpp(14) : 参见“Grand::Grand”的声明 设计一个不能被继承的类.cpp(9) : 参见“Grand”的声明 此诊断出现在编译器生成的函数“Son::Son(void)”中*/class Son:public Parent{};int main(){ Son s; system("pause");}/* 1. 友元不属于任何类,但需要在类的内部声明,声明时需要加friend关键字 2. 友元函数可访问类的私有成员,但不是类的成员函数; 3. 友元函数不能用const修饰; 4. 友元函数可以在类定义的任何地方声明,不受类访问限定 符限制; 5. 函数可以是多个类的友元函数; 6. 友元函数的调用与普通函数的调用和原理相同; 友元类:友元类的所有成员函数都可以是另一个类的友元函数, 都可以访问另一个类中的非公有成员;*//* 友元的优缺点 优点:提高了程序运行效率 缺点:破坏了类的封装性和隐藏性 注意: 友元关系不能继承; 友元关系是单向的,不具有交换性; 友元关系不能传递;*/
快速排序
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法
#include<iostream>using namespace std;//普通法int partion1(int *arr, int left, int right){ //快排若选用左边的为基准值,则指针应当从右边开始走 //反之若选右边的则应当从左边走 /* 如本例,若从左边开始走则 2, 1, 6, 3, 4, 5, 9, 5, 0 2 1 0* 3 4 5 9 5 *6 这时begin在3位置,end也会走到3位置,循环结束 交换arr[left]与arr[begin] 2 1 0 3 4 5 9 5 6 3 1 0 2 4 5 9 5 6 结果不对。 arr[end]>=key arr[begin] <=key 必须都是大于等于或小于等于号,不能没有等号, */ int key = arr[left]; int begin = left; int end = right-1; while (begin < end) { while (begin<end&&arr[end]>=key) --end; while (begin < end&&arr[begin] <=key) ++begin; if (begin < end) swap(arr[begin], arr[end]); } swap(arr[begin], arr[left]); return begin;}//挖坑法int partion2(int *arr, int left, int right){ int key = arr[left]; int end = right - 1; int begin = left; while (begin < end) { while (begin<end&&arr[end]>=key) --end; arr[begin] = arr[end]; while (begin < end&&arr[begin] <= key) ++begin; arr[end] = arr[begin]; } arr[begin] = key; return begin;}//极简双指针法int partion3(int *arr, int left, int right){ int pCur = left; int pPre = left - 1; /* 例 2, 1, 6, 3, 4, 5, 9, 5, 4 2 1 3 *6 #4 5 9 5 4 2 1 3 *4 4 5 9 5 6 */ while (pCur < right) { while (arr[pCur] < arr[right - 1] && ++pPre != pCur) swap(arr[pCur], arr[pPre]); pCur++; } swap(arr[++pPre], arr[right - 1]); return pPre;}void qSort(int *arr,int left, int right){ if (right - left < 2) return; if (left < right) { int Boundary = partion3(arr, left, right); qSort(arr, left, Boundary); qSort(arr, Boundary+1, right); }}int main(){ int arr[] = { 2, 1, 6, 3, 4, 5, 9, 5, 0 }; int len = sizeof(arr) / sizeof(arr[0]); qSort(arr, 0,len); for (int i = 0; i < len; i++) { cout << arr[i] << " "; } cout << endl; system("pause");}
N皇后问题
/* 1.用一个数组保存之前放置皇后的位置,如arr[i]=j,则代表第i行第j列放置了皇后 2. 以行为基准,行每次自增,判断列是否放置合法。*/#include<iostream>using namespace std;bool isleagle(int *arr, int i, int j){ for (int k = 0; k < i; k++) { if (j == arr[k] || abs(arr[k] - j) == abs(i - k)) { return false; } } return true;}int getNum(int i, int *arr, int n){ if (i == n) return 1; int res = 0; for (int j = 0; j < n; j++) { if (isleagle(arr, i, j)) { arr[i] = j; //每次递归递归到i==n说明有一条路了,然后返回到上一层, //上一层的i是n-1这时,j再换一个格子就是j++,然后继续 //递归到n则又有一条路。于是所有路经都计算到了 res += getNum(i + 1, arr, n); } } return res;}int gethuanghou(int n){ if (n < 1) return 0; int *arr = new int[n]; return getNum(0, arr, n);}int main(){ int n; while (cin >> n) cout << gethuanghou(n) << endl; system("pause"); return 0;}
插入排序
#include<iostream>using namespace std;void InsertSort(int *arr, int len){ if (len < 2) return; for (int i = 0; i < len; i++) { int j = i - 1; int key = arr[i]; while (j>-1 && arr[j]>key) { arr[j + 1] = arr[j]; --j; } arr[j + 1] = key; }}int main(){ int arr[] = { 2, 3, 1, 5, 12, 3, 7, 3, 9, 3, 0, 2 }; int len = sizeof(arr) / sizeof(arr[0]); InsertSort(arr, len); for (int i = 0; i < len; i++) { cout << arr[i] << " "; } cout << endl; system("pause"); return 0;}
堆排序
#include<iostream>using namespace std;class Heap_Sort{public: void Sort(int *arr, int len) { _Build_Heap(arr, len); while (len > 1) { swap(arr[0], arr[len - 1]); len--; _AdjustDown(arr,0,len); } }private: void _Build_Heap(int *arr, int len) { for (int i = ((len - 2) >> 1); i >= 0; i--) { _AdjustDown(arr, i,len); } } void _AdjustDown(int *arr, int root,int size) { int parent = root; int child = 2 * parent + 1; while (child <size) { if (child < size&&arr[child] < arr[child + 1]) child += 1; if (child < size&&arr[parent] < arr[child]) { swap(arr[parent], arr[child]); parent = child; child = 2 * parent + 1; } else break; } }};int main(){ int arr[] = { 5, 3, 1, 7, 4, 0, 6, 8, 4, 7 }; int len = sizeof(arr) / sizeof(arr[0]); Heap_Sort s; s.Sort(arr, len); for (int i = 0; i < len; i++) cout << arr[i] << " "; cout << endl; system("pause");}
冒泡排序
#include<iostream>using namespace std;//注意第二个条件是j<len-i-1void BubbleSort(int *arr, int len){ if (len < 2) return; bool flag = true; for (int i = 0; i < len; i++) { for (int j = 0; j < len - i - 1; j++) { if (arr[j] >arr[j + 1]) { swap(arr[j], arr[j + 1]); flag = false; } } if (flag) return; }}int main(){ int arr[] = { 2, 3, 1, 5, 12, 3, 7, 3, 9, 3, 0, 2 }; int len = sizeof(arr) / sizeof(arr[0]); BubbleSort(arr, len); for (int i = 0; i < len; i++) { cout << arr[i] << " "; } cout << endl; system("pause"); return 0;}
merge归并排序
#include<iostream>#include<cassert>using namespace std;void Merge(int *arr, int left,int mid, int right, int *temp){ int begin1 = left; int end1 = mid; int begin2 = mid + 1; int end2 = right; int idx = left; while (begin1 <= end1&&begin2<=end2) { if (arr[begin1] < arr[begin2]) temp[idx++] = arr[begin1++]; else temp[idx++] = arr[begin2++]; } while (begin1<=end1) temp[idx++] = arr[begin1++]; while (begin2<=end2) temp[idx++] = arr[begin2++]; for (int i = left; i<=right; i++) arr[i] = temp[i];}void _Merge_Sort(int *arr, int left, int right, int *temp){ if (right > left) { int mid = left + ((right - left) >> 1); _Merge_Sort(arr, left, mid, temp); _Merge_Sort(arr, mid + 1, right, temp); Merge(arr, left, mid,right, temp); }}void Merge_Sort(int *arr, int left, int right){ assert(right - left > 1); int *temp = new int[right - left + 1]; _Merge_Sort(arr, left, right, temp); delete[]temp;}int main(){ int arr[] = { 2, 3, 45, 2, 5, 1, 8, 5, 2, 3, 0 }; int len = sizeof(arr) / sizeof(arr[0]); Merge_Sort(arr, 0, len-1); for (int i = 0; i < len; i++) { cout <<arr[i] << " "; } cout << endl; system("pause");}
只能在栈上生成对象
/*只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可。代码如下:*/#include<iostream>using namespace std;class Base{private: void *operator new(size_t); void operator delete(void *);public: Base() {} ~Base();};int main(){ Base *ptr = new Base;}
只能在堆上生成对象
/*容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象,只能使用new运算符来建立对象。然而,前面已经说过,new运算符的执行过程分为两步,C++提供new运算符的重载,其实是只允许重载operator new()函数,而operator()函数用于分配内存,无法提供构造功能。因此,这种方法不可以。当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。如果编译器无法调用类的析构函数,情况会是怎样的呢?比如,类的析构函数是私有的,编译器无法调用析构函数来释放内存。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下:class A{public : A(){} void destory(){ delete this ;}private : ~A(){}};*//*试着使用A a;来建立对象,编译报错,提示析构函数无法访问。这样就只能使用new操作符来建立对象,构造函数是公有的,可以直接调用。类中必须提供一个destory函数,来进行内存空间的释放。类对象使用完成后,必须调用destory函数。上述方法的一个缺点就是,无法解决继承问题。如果A作为其它类的基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。还好C++提供了第三种访问控制,protected。将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类则可以访问。另一个问题是,类的使用很不方便,使用new建立对象,却使用destory函数释放对象,而不是使用delete。(使用delete会报错,因为delete对象的指针,会调用对象的析构函数,而析构函数类外不可访问)这种使用方式比较怪异。为了统一,可以将构造函数设为protected,然后提供一个public的static函数来完成构造,这样不使用new,而是使用一个函数来构造,使用一个函数来析构。代码如下,类似于单例模式:*/#include<iostream>using namespace std;class Base{private: Base() {} ~Base() {}public: static Base* getInstance() { return new Base; } void destory() { delete this; }};int main(){ Base *b = Base::getInstance();}
两个栈实现一个队列
#include<iostream>#include<stack>using namespace std;template<class T>class StackQueue{public: void Push(T data) { //Spush的入栈就相当于入队 Spush.push(data); } void Pop() { /* 如果Spop为空,则一直将sPush里面的元素压入Spop中 直到Spush为空,然后Spop弹出,就相当于入队 如果Spop不为空则直接弹出,就相当于出队 */ if (Spop.empty()) { while (!Spush.empty()) { Spop.push(Spush.top()); Spush.pop(); } } Spop.pop(); } T Front() { if (Spop.empty()) { while (!Spush.empty()) { Spop.push(Spush.top()); Spush.pop(); } } return Spop.top(); } bool empty() { return Spop.empty() && Spush.empty(); }private: stack<T> Spush; stack<T> Spop;};int main(){ StackQueue<int> q; q.Push(1); q.Pop(); q.Push(2); q.Push(3); q.Pop(); q.Pop(); cout << q.empty() << endl; //cout << q.Front() << endl; system("pause"); return 0;}
有getMin功能的栈
#include<iostream>#include<stack>#include<cstdio>using namespace std;/* 注意 1. 在得到Min值时,首先要判断stack是否为空,不为空再getMin 2. Min在pop时要判断pop的元素是否为当前的最小元素*/template<class T>class MinStack{public: T Top() { return _stack.top(); } void Push(T data) { _stack.push(data); if (_Min.empty() || data < _Min.top()) { _Min.push(data); } } bool Empty() { return _stack.empty(); } void Pop() { if (_stack.top() == _Min.top()) _Min.pop(); _stack.pop(); } T getMin() { //注意在getMin是要判断栈是否为空 if (_stack.empty()) { return INT_MAX; } return _Min.top(); }private: stack<T> _stack; stack<T> _Min;};int main(){ /*MinStack<int> s; s.Push(1); s.Push(4); s.Push(5); s.Push(0); cout << s.getMin() << endl; cout << INT_MAX << endl; system("pause");*/ MinStack<int> st; char s[100]; int op; while (scanf("%s", s) == 1 && strcmp(s, "END") != 0) { if (strcmp(s, "PUSH") == 0) { scanf("%d", &op); st.Push (op); printf("push=%d\n", op); } else if (strcmp(s, "POP") == 0) { op = st.Top(); st.Pop(); printf("pop=%d\n", op); } else if (strcmp(s, "TOP") == 0) { printf("top=%d\n", st.Top()); } else if (strcmp(s, "MIN") == 0) { printf("min=%d\n", st.getMin()); } } return 0;}
阅读全文
3 0
- 多态&指针访问虚函数&不能被继承的类&快速排序&N皇后问题&插入排序&堆排序&merge归并排序&栈上生成对象&两个栈实现一个队列
- 插入排序、选择排序、归并排序、堆排序、快速排序的JAVA实现
- 冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序java实现
- 常见比较排序算法的实现(归并排序、快速排序、堆排序、选择排序、插入排序、希尔排序)
- 几种基本排序的实现:选择排序,冒泡排序,插入排序,堆排序,快速排序,归并排序
- 插入排序、希尔排序、堆排序、归并排序、快速排序
- 排序总结(代码实现):选择排序,插入排序,归并排序,快速排序,堆排序
- 排序算法的C++实现与性能分析(插入排序、归并排序、快速排序、STOOGE排序、堆排序)
- 排序:插入,希尔,堆,快速,归并排序
- 插入排序,快速排序,堆排序,归并排序
- 数据结构:插入排序/冒泡排序/快速排序/归并排序/堆排序 C#语言实现
- 快速排序、归并排序、堆排序的实现
- 快速排序,归并排序,堆排序的java代码实现
- 快速排序、堆排序、归并排序的python实现
- 基本的排序算法:冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序
- java(Merge) 实现归并排序,快速排序
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- java实现各种基础排序(冒泡排序、快速排序、直接选择排序、堆排序、直接插入排序、归并排序)
- 如何使用Linux
- vue.js开发环境搭建以及脚手架工具安装
- 1.简单工厂模式
- 阻塞和非阻塞-同步和异步-BIONIOAIO
- Angular4 中使用Pug/Jade
- 多态&指针访问虚函数&不能被继承的类&快速排序&N皇后问题&插入排序&堆排序&merge归并排序&栈上生成对象&两个栈实现一个队列
- PHP之简单工厂模式
- spoj10606 Balanced Numbers
- SpringMVC配置静态资源
- Python 练习14---if...in
- 牛客剑指offer刷题记录(二)
- angularjs指令的独立作用域和绑定策略
- fork()系统调用的特性
- Ubuntu16 编译Android5.1 lollipop 源码出错 unsupported reloc 43