【C++】面向?qū)ο笾瓹++模板-005

第五章 C++模板


5.1 模板概論


c++提供了函數(shù)模板(function template.)所謂函數(shù)模板梧油,實際上是建立一個通用函數(shù)撵儿,其函數(shù)類型和形參類型不具體制定再榄,用一個虛擬的類型來代表蝙叛。這個通用函數(shù)就成為函數(shù)模板乳绕。 凡是函數(shù)體相同的函數(shù)都可以用這個模板代替绞惦,不必定義多個函數(shù),只需在模板中定義一次即可洋措。在調(diào)用函數(shù)時系統(tǒng)會根據(jù)實參的類型來取代模板中的虛擬類型济蝉,從而實現(xiàn)不同函數(shù)的功能。

  • c++提供兩種模板機制:函數(shù)模板類模板
  • 類屬 - 類型參數(shù)化菠发,又稱參數(shù)模板

總結(jié):

  • 模板把函數(shù)或類要處理的數(shù)據(jù)類型參數(shù)化王滤,表現(xiàn)為參數(shù)的多態(tài)性,成為類屬滓鸠。
  • 模板用于表達(dá)邏輯結(jié)構(gòu)相同雁乡,但具體數(shù)據(jù)元素類型不同的數(shù)據(jù)對象的通用行為。

5.2 函數(shù)模板


5.2.1 什么是函數(shù)模板糜俗?

//交換int數(shù)據(jù)
void SwapInt(int& a,int& b){
    int temp = a;
    a = b;
    b = temp;
}

//交換char數(shù)據(jù)
void SwapChar(char& a,char& b){
    char temp = a;
    a = b;
    b = temp;
}
//問題:如果我要交換double類型數(shù)據(jù)踱稍,那么還需要些一個double類型數(shù)據(jù)交換的函數(shù)
//繁瑣,寫的函數(shù)越多吩跋,當(dāng)交換邏輯發(fā)生變化的時候寞射,所有的函數(shù)都需要修改渔工,無形當(dāng)中增加了代碼的維護難度

//如果能把類型作為參數(shù)傳遞進(jìn)來就好了锌钮,傳遞int就是Int類型交換,傳遞char就是char類型交換
//我們有一種技術(shù)引矩,可以實現(xiàn)類型的參數(shù)化---函數(shù)模板


//class 和 typename都是一樣的梁丘,用哪個都可以
template<class T>
void MySwap(T& a,T& b){
    T temp = a;
    a = b;
    b = temp;
}

void test01(){
    
    int a = 10;
    int b = 20;
    cout << "a:" << a << " b:" << b << endl;
    //1. 這里有個需要注意點,函數(shù)模板可以自動推導(dǎo)參數(shù)的類型
    MySwap(a,b);
    cout << "a:" << a << " b:" << b << endl;

    char c1 = 'a';
    char c2 = 'b';
    cout << "c1:" << c1 << " c2:" << c2 << endl;
    //2. 函數(shù)模板可以自動類型推導(dǎo)旺韭,那么也可以顯式指定類型
    MySwap<char>(c1, c2);
    cout << "c1:" << c1 << " c2:" << c2 << endl;
}

用模板是為了實現(xiàn)泛型氛谜,可以減輕編程的工作量,增強函數(shù)的重用性区端。

5.2.2 課堂練習(xí)

使用函數(shù)模板實現(xiàn)對char和int類型數(shù)組進(jìn)行排序值漫?

//模板打印函數(shù)
template<class T>
void PrintArray(T arr[],int len){
    for (int i = 0; i < len;i++){
        cout << arr[i] << " ";
    }
    cout << endl;
}

//模板排序函數(shù)
template<class T>
void MySort(T arr[],int len){
    
    for (int i = 0; i < len;i++){
        for (int j = len - 1; j > i;j--){
            if (arr[j] > arr[j - 1]){
                T temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
            }
        }
    }

}

void test(){
    
    //char數(shù)組
    char tempChar[] = "aojtifysn";
    int charLen = strlen(tempChar);

    //int數(shù)組
    int tempInt[] = {7,4,2,9,8,1};
    int intLen = sizeof(tempInt) / sizeof(int);

    //排序前 打印函數(shù)
    PrintArray(tempChar, charLen);
    PrintArray(tempInt, intLen);
    //排序
    MySort(tempChar, charLen);
    MySort(tempInt, intLen);
    //排序后打印
    PrintArray(tempChar, charLen);
    PrintArray(tempInt, intLen);
}

5.3 函數(shù)模板和普通函數(shù)區(qū)別


  • 函數(shù)模板不允許自動類型轉(zhuǎn)化
  • 普通函數(shù)能夠自動進(jìn)行類型轉(zhuǎn)化
//函數(shù)模板
template<class T>
T MyPlus(T a, T b){
    T ret = a + b;
    return ret;
}

//普通函數(shù)
int MyPlus(int a,char b){
    int ret = a + b;
    return ret;
}

void test02(){

    int a = 10;
    char b = 'a';

    //調(diào)用函數(shù)模板,嚴(yán)格匹配類型
    MyPlus(a, a);
    MyPlus(b, b);
    //調(diào)用普通函數(shù)
    MyPlus(a, b);
    //調(diào)用普通函數(shù)  普通函數(shù)可以隱式類型轉(zhuǎn)換
    MyPlus(b, a);

    //結(jié)論:
    //函數(shù)模板不允許自動類型轉(zhuǎn)換织盼,必須嚴(yán)格匹配類型
    //普通函數(shù)可以進(jìn)行自動類型轉(zhuǎn)換
}

5.4 函數(shù)模板和普通函數(shù)在一起調(diào)用規(guī)則


  • c++編譯器優(yōu)先考慮普通函數(shù)
  • 可以通過空模板實參列表的語法限定編譯器只能通過模板匹配
  • 函數(shù)模板可以像普通函數(shù)那樣可以被重載
  • 如果函數(shù)模板可以產(chǎn)生一個更好的匹配杨何,那么選擇模板
//函數(shù)模板
template<class T>
T MyPlus(T a, T b){
    T ret = a + b;
    return ret;
}

//普通函數(shù)
int MyPlus(int a, int b){
    int ret = a + b;
    return ret;
}

void test03(){
    int a = 10;
    int b = 20;
    char c = 'a';
    char d = 'b';
    //如果函數(shù)模板和普通函數(shù)都能匹配,c++編譯器優(yōu)先考慮普通函數(shù)
    cout << MyPlus(a, b) << endl;
    //如果我必須要調(diào)用函數(shù)模板,那么怎么辦?
    cout << MyPlus<>(a, b) << endl;
    //此時普通函數(shù)也可以匹配沥邻,因為普通函數(shù)可以自動類型轉(zhuǎn)換
    //但是此時函數(shù)模板能夠有更好的匹配
    //如果函數(shù)模板可以產(chǎn)生一個更好的匹配危虱,那么選擇模板
    cout << MyPlus(c,d);
}

//函數(shù)模板重載
template<class T>
T MyPlus(T a, T b, T c){
    T ret = a + b + c;
    return ret;
}

void test04(){

    int a = 10;
    int b = 20;
    int c = 30;
    cout << MyPlus(a, b, c) << endl;
    //如果函數(shù)模板和普通函數(shù)都能匹配,c++編譯器優(yōu)先考慮普通函數(shù)
}

5.5 模板機制剖析


思考:為什么函數(shù)模板可以和普通函數(shù)放在一起?c++編譯器是如何實現(xiàn)函數(shù)模板機制的唐全?

5.5.1編譯過程

hello.cpp程序是高級c語言程序埃跷,這種程序易于被人讀懂。為了在系統(tǒng)上運行hello.c程序,每一條c語句都必須轉(zhuǎn)化為低級的機器指令弥雹。然后將這些機器指令打包成可執(zhí)行目標(biāo)文件格式垃帅,并以二進(jìn)制形式存儲于磁盤中。
預(yù)處理(Pre-processing) -> 編譯(Compiling) ->匯編(Assembling) -> 鏈接(Linking)

在這里插入圖片描述

5.5.2 模板實現(xiàn)機制

數(shù)模板機制結(jié)論:

  • 編譯器并不是把函數(shù)模板處理成能夠處理任何類型的函數(shù)
  • 函數(shù)模板通過具體類型產(chǎn)生不同的函數(shù)
  • 編譯器會對函數(shù)模板進(jìn)行兩次編譯缅糟,在聲明的地方對模板代碼本身進(jìn)行編譯挺智,在調(diào)用的地方對參數(shù)替換后的代碼進(jìn)行編譯。

5.6模板的局限性


假設(shè)有如下模板函數(shù):

    template<class T>
    void f(T a, T b)
    { … }

如果代碼實現(xiàn)時定義了賦值操作 a = b窗宦,但是T為數(shù)組赦颇,這種假設(shè)就不成立了
同樣,如果里面的語句為判斷語句 if(a>b),但T如果是結(jié)構(gòu)體赴涵,該假設(shè)也不成立媒怯,另外如果是傳入的數(shù)組,數(shù)組名為地址髓窜,因此它比較的是地址扇苞,而這也不是我們所希望的操作。

總之寄纵,編寫的模板函數(shù)很可能無法處理某些類型鳖敷,另一方面,有時候通用化是有意義的程拭,但C++語法不允許這樣做定踱。為了解決這種問題,可以提供模板的重載恃鞋,為這些特定的類型提供具體化的模板崖媚。

class Person
{
public:
    Person(string name, int age)
    {
        this->mName = name;
        this->mAge = age;
    }
    string mName;
    int mAge;
};

//普通交換函數(shù)
template <class T>
void mySwap(T &a,T &b)
{
    T temp = a;
    a = b; 
    b = temp;
}
//第三代具體化,顯示具體化的原型和定意思以template<>開頭恤浪,并通過名稱來指出類型
//具體化優(yōu)先于常規(guī)模板
template<>void  mySwap<Person>(Person &p1, Person &p2)
{
    string nameTemp;
    int ageTemp;

    nameTemp = p1.mName;
    p1.mName = p2.mName;
    p2.mName = nameTemp;

    ageTemp = p1.mAge;
    p1.mAge = p2.mAge;
    p2.mAge = ageTemp;

}

void test()
{
    Person P1("Tom", 10);
    Person P2("Jerry", 20);

    cout << "P1 Name = " << P1.mName << " P1 Age = " << P1.mAge << endl;
    cout << "P2 Name = " << P2.mName << " P2 Age = " << P2.mAge << endl;
    mySwap(P1, P2);
    cout << "P1 Name = " << P1.mName << " P1 Age = " << P1.mAge << endl;
    cout << "P2 Name = " << P2.mName << " P2 Age = " << P2.mAge << endl;
}

5.7 類模板


5.7.1 類模板基本概念

類模板和函數(shù)模板的定義和使用類似畅哑,我們已經(jīng)進(jìn)行了介紹。有時水由,有兩個或多個類荠呐,其功能是相同的,僅僅是數(shù)據(jù)類型不同砂客。

  • 類模板用于實現(xiàn)類所需數(shù)據(jù)的類型參數(shù)化
template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->mName = name;
        this->mAge = age;
    }
    void showPerson()
    {
        cout << "name: " << this->mName << " age: " << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};

void test01()
{
    //Person P1("德瑪西亞",18); // 類模板不能進(jìn)行類型自動推導(dǎo) 
    Person<string, int>P1("德瑪西亞", 18);
    P1.showPerson();
}

5.7.2 類模板做函數(shù)參數(shù)

//類模板
template<class NameType, class AgeType>
class Person{
public:
    Person(NameType name, AgeType age){
        this->mName = name;
        this->mAge = age;
    }
    void PrintPerson(){
        cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};

//類模板做函數(shù)參數(shù)
void DoBussiness(Person<string,int>& p){
    p.mAge += 20;
    p.mName += "_vip";
    p.PrintPerson();
}

int main(){

    Person<string, int> p("John", 30);
    DoBussiness(p);

    system("pause");
    return EXIT_SUCCESS;
}

5.7.3 類模板派生普通類

//類模板
template<class T>
class MyClass{
public:
    MyClass(T property){
        this->mProperty = property;
    }
public:
    T mProperty;
};

//子類實例化的時候需要具體化的父類泥张,子類需要知道父類的具體類型是什么樣的
//這樣c++編譯器才能知道給子類分配多少內(nèi)存

//普通派生類
class SubClass : public MyClass<int>{
public:
    SubClass(int b) : MyClass<int>(20){
        this->mB = b;
    }
public:
    int mB;
};

5.7.4 類模板派生類模板

//父類類模板
template<class T>
class Base
{
    T m;
};
template<class T >
class Child2 : public Base<double>  //繼承類模板的時候,必須要確定基類的大小
{
public:
    T mParam;
};

void test02()
{
    Child2<int> d2;
}

5.7.5 類模板類內(nèi)實現(xiàn)

template<class NameType, class AgeType>
class Person
{
public:
    Person(NameType name, AgeType age)
    {
        this->mName = name;
        this->mAge = age;
    }
    void showPerson()
    {
        cout << "name: " << this->mName << " age: " << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};

void test01()
{
    //Person P1("德瑪西亞",18); // 類模板不能進(jìn)行類型自動推導(dǎo) 
    Person<string, int>P1("德瑪西亞", 18);
    P1.showPerson();
}

5.7.6 類模板類外實現(xiàn)

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

template<class T1, class T2>
class Person{
public:
    Person(T1 name, T2 age);
    void showPerson();

public:
    T1 mName;
    T2 mAge;
};


//類外實現(xiàn)
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
    this->mName = name;
    this->mAge = age;
}


template<class T1, class T2>
void Person<T1, T2>::showPerson(){
    cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

void test()
{
    Person<string, int> p("Obama", 20);
    p.showPerson();
}

int main(){

    test();

    system("pause");
    return EXIT_SUCCESS;
}

5.7.7 類模板頭文件和源文件分離問題

Person.hpp

#pragma once

template<class T1,class T2>
class Person{
public:
    Person(T1 name,T2 age);
    void ShowPerson();
public:
    T1 mName;
    T2 mAge;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age){
    this->mName = name;
    this->mAge = age;
}

template<class T1, class T2>
void Person<T1, T2>::ShowPerson(){
    cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
}

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>
#include"Person.hpp"

//模板二次編譯
//編譯器編譯源碼 逐個編譯單元編譯的

int main(){

    Person<string, int> p("Obama", 20);
    p.ShowPerson();


    system("pause");
    return EXIT_SUCCESS;
}

結(jié)論:
案例代碼在qt編譯器順利通過編譯并執(zhí)行鞭盟,但是在Linuxvs編輯器下如果只包含頭文件圾结,那么會報錯鏈接錯誤,需要包含cpp文件齿诉,但是如果類模板中有友元類筝野,那么編譯失斏我Α!

解決方案: 類模板的聲明和實現(xiàn)放到一個文件中歇竟,我們把這個文件命名為.hpp(這個是個約定的規(guī)則挥唠,并不是標(biāo)準(zhǔn),必須這么寫).

原因:

  • 類模板需要二次編譯焕议,在出現(xiàn)模板的地方編譯一次宝磨,在調(diào)用模板的地方再次編譯。
  • C++編譯規(guī)則為獨立編譯盅安。

5.7.8 模板類碰到友元函數(shù)

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

template<class T1, class T2> class Person;
//告訴編譯器這個函數(shù)模板是存在
template<class T1, class T2> void PrintPerson2(Person<T1, T2>& p);

//友元函數(shù)在類內(nèi)實現(xiàn)
template<class T1, class T2>
class Person{
    //1. 友元函數(shù)在類內(nèi)實現(xiàn)
    friend void PrintPerson(Person<T1, T2>& p){
        cout << "Name:" << p.mName << " Age:" << p.mAge << endl;
    }

    //2.友元函數(shù)類外實現(xiàn)
    //告訴編譯器這個函數(shù)模板是存在
    friend void PrintPerson2<>(Person<T1, T2>& p);

    //3. 類模板碰到友元函數(shù)模板
    template<class U1, class U2>
    friend void PrintPerson(Person<U1, U2>& p);

public:
    Person(T1 name, T2 age){
        this->mName = name;
        this->mAge = age;
    }
    void showPerson(){
        cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
    }
private:
    T1 mName;
    T2 mAge;
};

void test01()
{
    Person <string, int>p("Jerry", 20);
    PrintPerson(p);
}


// 類模板碰到友元函數(shù)
//友元函數(shù)類外實現(xiàn)  加上<>空參數(shù)列表唤锉,告訴編譯去匹配函數(shù)模板
template<class T1 , class T2>
void PrintPerson2(Person<T1, T2>& p)
{
    cout << "Name2:" << p.mName << " Age2:" << p.mAge << endl;
}

void  test02()
{
    Person <string, int>p("Jerry", 20);
    PrintPerson2(p);   //不寫可以編譯通過,寫了之后别瞭,會找PrintPerson2的普通函數(shù)調(diào)用窿祥,因為寫了普通函數(shù)PrintPerson2的聲明    
}

int main(){

    //test01();
    test02();
    system("pause");
    return EXIT_SUCCESS;
}

5.8 類模板的應(yīng)用


設(shè)計一個數(shù)組模板類(MyArray),完成對不同類型元素的管理

#pragma once
template<class T>
class MyArray
{
public:
    explicit MyArray(int capacity)
    {
        this->m_Capacity = capacity;
        this->m_Size = 0;
        // 如果T是對象,那么這個對象必須提供默認(rèn)的構(gòu)造函數(shù)
        pAddress = new T[this->m_Capacity];
    }

    //拷貝構(gòu)造
    MyArray(const MyArray & arr)
    {
        this->m_Capacity = arr.m_Capacity;
        this->m_Size = arr.m_Size;
        this->pAddress = new T[this->m_Capacity];
        for (int i = 0; i < this->m_Size;i++)
        {
            this->pAddress[i] = arr.pAddress[i];
        }
    }

    //重載[] 操作符  arr[0]
    T& operator [](int index)
    {
        return this->pAddress[index]; 
    }
    //尾插法
    void Push_back(const T & val)
    {
        if (this->m_Capacity == this->m_Size)
        {
            return;
        }
        this->pAddress[this->m_Size] = val;
        this->m_Size++;
    }
    void Pop_back()
    {
        if (this->m_Size == 0)
        {
            return;
        }
        this->m_Size--;
    }
    int getSize()
    {
        return this->m_Size;
    }
    //析構(gòu)
    ~MyArray()
    {
        if (this->pAddress != NULL)
        {
            delete[] this->pAddress;
            this->pAddress = NULL;
            this->m_Capacity = 0; 
            this->m_Size = 0;
        }
    }

private:
    T * pAddress;  //指向一個堆空間蝙寨,這個空間存儲真正的數(shù)據(jù)
    int m_Capacity; //容量
    int m_Size;   // 大小
};

測試代碼:


class Person{
public:
    Person(){}
    Person(string name, int age){
        this->mName = name;
        this->mAge = age;
    }
public:
    string mName;
    int mAge;
};


void PrintMyArrayInt(MyArray<int>& arr){
    for (int i = 0; i < arr.getSize(); i++){
        cout << arr[i] << " ";
    }
    cout << endl;
}

void PrintMyPerson(MyArray<Person>& personArr)
{
    for (int i = 0; i < personArr.getSize(); i++){
        cout << "姓名:" << personArr[i].mName << " 年齡: " << personArr[i].mAge << endl;
    }
    
}
    
    MyArray<int> myArrayInt(10);
    for (int i = 0; i < 9; i++)
    {
        myArrayInt.Push_back(i);
    }
    myArrayInt.Push_back(100);
    PrintMyArrayInt(myArrayInt);

MyArray<Person> myArrayPerson(10);
    Person p1("德瑪西亞", 30);
    Person p2("提莫", 20);
    Person p3("孫悟空",18);
    Person p4("趙信", 15);
    Person p5("趙云", 24);
    myArrayPerson.Push_back(p1);
    myArrayPerson.Push_back(p2);
    myArrayPerson.Push_back(p3);
    myArrayPerson.Push_back(p4);
    myArrayPerson.Push_back(p5);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晒衩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墙歪,更是在濱河造成了極大的恐慌听系,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虹菲,死亡現(xiàn)場離奇詭異靠胜,居然都是意外死亡,警方通過查閱死者的電腦和手機届惋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門髓帽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菠赚,“玉大人脑豹,你說我怎么就攤上這事『獠椋” “怎么了瘩欺?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拌牲。 經(jīng)常有香客問我俱饿,道長,這世上最難降的妖魔是什么塌忽? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任拍埠,我火速辦了婚禮,結(jié)果婚禮上土居,老公的妹妹穿的比我還像新娘枣购。我一直安慰自己嬉探,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布棉圈。 她就那樣靜靜地躺著涩堤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪分瘾。 梳的紋絲不亂的頭發(fā)上胎围,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音德召,去河邊找鬼白魂。 笑死,一個胖子當(dāng)著我的面吹牛上岗,可吹牛的內(nèi)容都是我干的碧聪。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼液茎,長吁一口氣:“原來是場噩夢啊……” “哼逞姿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捆等,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤滞造,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后栋烤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谒养,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年明郭,在試婚紗的時候發(fā)現(xiàn)自己被綠了买窟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡薯定,死狀恐怖始绍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情话侄,我是刑警寧澤亏推,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站年堆,受9級特大地震影響吞杭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜变丧,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一芽狗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痒蓬,春花似錦童擎、人聲如沸曼月。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哑芹。三九已至,卻和暖如春捕透,著一層夾襖步出監(jiān)牢的瞬間聪姿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工乙嘀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留末购,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓虎谢,卻偏偏與公主長得像盟榴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子婴噩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容