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;
}

0722-----C++Primer听课笔记----------虚函数和模板,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。