0722-----C++Primer听课笔记----------虚函数和模板
1.虚指针和虚函数表
1.1 不含有任何数据成员或者虚函数的class或者struct大小为1,含有虚函数的对象在基地址部分有一个vptr,指向虚函数表,因此大小为4个字节。
1.2 动态绑定的原理:假设派生类和基类存在覆盖的关系(基类中定义了虚函数),那么派生类在虚函数表中,会覆盖掉基类相应的虚函数。当程序执行的时候,根据基类指针找到vptr,根据vptr找到vtable,然后找到相应的版本去执行。所以执行的是覆盖的版本,而具体被哪个版本覆盖是由具体的对象类型所决定的,所以才实现了根据对象的具体类型去调用相应的函数(参考资料:http://blog.csdn.net/haoel/article/details/1948051/)。
1.3 当类中含有虚函数的时候(不全面),需要把析构函数设为virtual析构函数。
1.3.1 如下例所示,当用基类的指针指向一个派生类的对象时,基类指针会把该内存空间当做是一个基类的对象,对后面派生类的空间不可见,因此,当析构的时候只析构了基类大小的空间,这就造成了资源释放不完全。
#include <iostream> using namespace std; /* * 基类指针指向子类对象空间 * 释放基类指针时会释放不完全 */ class Base{ public: Base(){ cout << "Base..." << endl; } ~Base(){ cout << "~Base..." << endl; } }; class Derived : public Base{ public: Derived(){ cout << "Derived..." << endl; } ~Derived(){ cout << "~Derived..." << endl; } }; int main(int argc, const char *argv[]) { Base *bp = new Derived(); delete bp; //这里只调用了基类的析构函数 派生类的地址空间没有被释放 return 0; }
1.3.2 当把基类的析构函数设为为虚函数时,在回收资源的时候会根据实际的类型动态绑定,将资源全部回收。
1.4 函数声明为virtual,意味着需要由用户去继承,以重新实现。
1.5 不要试图重定义基类的非virtual函数。
1.6 虚函数尤其是纯虚函数,相当于制定了一种约定、契约,凡是继承并改写(或者实现纯虚函数)的子类,都必须遵守这一约定。
#ifndef __THREAD_H__ #define __THREAD_H__ #include <pthread.h> class Thread{ public: Thread(); virtual ~Thread(){} void start(); static void* thread_func(void *); virtual void run() = 0; void join(); private: pthread_t tid; }; #endif #include "thread.h" #include <iostream> Thread::Thread() :tid(-1) { } void Thread::start(){ pthread_create(&tid, NULL, thread_func, this); } void *Thread::thread_func(void *arg){ Thread *pt = static_cast<Thread *>(arg); pt->run(); //动态绑定 } void Thread::join(){ pthread_join(tid, NULL); } #include "thread.h" #include <iostream> #include <unistd.h> using namespace std; /* * 定义线程类 将执行的函数run定义为纯虚函数 * 由派生类实现不同的操作 */ class TestThread : public Thread{ public: void run(){ while(1){ sleep(1); cout << "hello ..." << endl; } } }; int main(int argc, const char *argv[]) { TestThread th; th.start(); th.join(); return 0; }
2.模板的编写
2.1几个简单的模板
2.1.1 程序,这里要注意 模板使用template关键字,尖括号内的类型定义可以使用typename,也可以定义为常量,即为非类型模板形参。。
#include <iostream> #include <string> #include <vector> using namespace std; /* * 两个参数的类型可以不同 */ template <typename T1, typename T2> T1 add(const T1 &a, const T2 &b){ return a + b; } int main(int argc, const char *argv[]) { cout << add(2, 2.3) << endl; return 0; }
2.1.2 程序2。这里T::size_type *p这句话在模板中存在歧义,可以把T::size_type解释成一种类型,所以这里定义了一个指针p,还可以把T::size_type解释成一个变量,所以这样可以看做乘法。解决方案就是在前面加上typename,来说明这是一个定义,而不是乘法。typename T::size_type *p。
#include <iostream> #include <string> #include <vector> using namespace std; template <typename T, typename V> void test(T a, V b){ //这里存在歧义 //T::size_type *p; typename T::size_type *p; } int main(int argc, const char *argv[]) { test(string("hello"), 8); return 0; }
3.2 模板类
3.2.1 编写模板类的注意事项:
a)类的声明和实现放到同一个hpp文件中;
b)所有的函数均为 inline;
c)每个函数在类外实现都要加上模板参数类表;
d)类名要写完整,例如SmartPtr<T>,不能漏掉尖括号,因为SmartPtr不是完整的类。
3.2.2 智能指针类模板
#ifndef __SMART_HPP__ #define __SMART_HPP__ #include <stddef.h> template <typename T> class Smartptr{ public: Smartptr(); Smartptr(T *); ~Smartptr(); void resetPtr(T *); //这里T不能为const const T *getPtr() const; T &operator*(); const T &operator*()const; T *operator->(); const T *operator->()const; operator bool() const; private: Smartptr(const T&); Smartptr operator= (const T&); T *ptr_; }; //智能指针模板类的实现 //每个函数在类外的实现都要加上模板参数列表 template <typename T> inline Smartptr<T>::Smartptr() //类名包括参数 :ptr_(NULL) { } template <typename T> inline Smartptr<T>::Smartptr(T* ptr) :ptr_(ptr) { } template <typename T> inline Smartptr<T>::~Smartptr(){ delete ptr_; } template <typename T> inline void Smartptr<T>::resetPtr(T *ptr){ if(ptr_ != ptr){ delete ptr_; ptr_ = ptr; } } template <typename T> inline const T *Smartptr<T>::getPtr()const{ return ptr_; } template <typename T> inline T &Smartptr<T>::operator*(){ return *ptr_; } template <typename T> inline const T &Smartptr<T>::operator*()const{ return *ptr_; } template <typename T> inline T *Smartptr<T>::operator->(){ return ptr_; } template <typename T> inline const T *Smartptr<T>::operator->() const{ return ptr_; } template <typename T> inline Smartptr<T>::operator bool() const{ return ptr_; } #endif #include "smartptr.hpp" #include <iostream> #include <assert.h> using namespace std; class Animal{ public: Animal(){ cout << "Animal ..." << endl; } ~Animal(){ cout << "~Animal..." << endl; } void display(){ cout << "in Animal..." << endl; } }; int main(int argc, const char *argv[]) { Smartptr<Animal> pt(new Animal); assert(pt); // 这里重载了bool类型 cout << pt.getPtr() << endl; pt.resetPtr(NULL); assert(pt == 0); cout << "------------" << endl; pt.resetPtr(new Animal); pt->display(); return 0; }
3.2.3 队列类模板
#ifndef __QUEUE_H__ #define __QUEUE_H__ #include <stddef.h> #include <assert.h> template <typename T> class Queue; //前向声明 用于 friend class template <typename T> class Node{ friend class Queue<T>; private: T data_; Node* next_; }; template <typename T> class Queue{ public: typedef Node<T> *NodePtr; // Queue(); Queue(const Queue &queue); Queue &operator=(const Queue &queue); ~Queue(); void push(const T &data); void pop(); void clear(); const T &top() const; bool isEmpty()const; size_t getSize()const; private: void copyElements(const Queue &queue); NodePtr head_; NodePtr tail_; size_t size_; }; template <typename T> inline Queue<T>::Queue() :head_(NULL), tail_(NULL), size_(0){ } template <typename T> inline void Queue<T>::copyElements(const Queue &queue){ NodePtr pCur = queue.head_; while(pCur != queue.tail_){ push(pCur->data_); pCur = pCur->next_; } } template <typename T> inline Queue<T> &Queue<T>::operator=(const Queue &queue){ clear(); copyElements(queue); } template <typename T> inline Queue<T>::Queue(const Queue &queue) :head_(NULL), tail_(NULL), size_(0) { copyElements(queue); } template <typename T> inline Queue<T>::~Queue(){ clear(); } template <typename T> inline void Queue<T>::push(const T &data){ NodePtr pt = new Node<T>; pt->data_ = data; pt->next_ = NULL; if(isEmpty()){ head_ = tail_ = pt; } else{ tail_->next_ = pt; tail_ = pt; } size_++; } template <typename T> inline void Queue<T>::pop(){ assert(!isEmpty()); NodePtr pt = head_; head_ = head_->next_; delete pt; } template <typename T> inline void Queue<T>::clear(){ while(!isEmpty()){ pop(); } } template <typename T> inline const T &Queue<T>::top() const{ assert(!isEmpty()); return head_->data_; } template <typename T> inline bool Queue<T>::isEmpty() const{ return head_ == NULL; } template <typename T> inline size_t Queue<T>::getSize()const{ return size_; } #endif #include "queue.hpp" #include <iostream> #include <assert.h> using namespace std; int main(int argc, const char *argv[]) { Queue<int> Q; Q.push(1); Q.push(2); while(!Q.isEmpty()){ cout << Q.top() << endl; Q.pop(); } return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。