C++复习篇

C语言模拟实现C++多态

基类指针/引用指向子类的实例,通过基类指针/引用调用子类成员函数。

复制代码
typedef void(*SoundFunc)(void*);
//虚函数表
typedef struct
{
    SoundFunc makesound;//叫声
}Vtable;

//基类
typedef struct
{
    const char* name;
    Vtable* table;
}Animal;

//实现子类虚函数(cat)
void Catsound(void *self){
    Animal* am=(Animal*)self;
    printf("%s:喵喵~;\n",am->name);
}

//Cat 虚函数表
Vtable CatVtable={
    .makesound=Catsound
};

//dog
void Dogsound(void *self){

    Animal* am=(Animal*)self;
    printf("%s:汪汪汪~~\n",am->name);
}

//Dog 虚函数表
Vtable DogVtable={
    .makesound=Dogsound
};

// 6. 子类构造函数(初始化基类属性和虚函数表)
Animal* CatCreate(const char* name)
{

    Animal* cat=(Animal*)malloc(sizeof(Animal));
    cat->name=name;
    cat->table=&CatVtable;
    return cat;
}

Animal* DogCreate(const char* name)
{
    Animal* dog=(Animal*)malloc(sizeof(Animal));
    dog->name=name;
    dog->table=&DogVtable;
    return dog;
}

// 7. 统一调用接口(核心:多态实现)
// 无需区分子类类型,直接通过基类指针调用虚函数表中的函数

void AnimalMakesound(Animal* animal)
{

    if(animal&&animal->table&&animal->table->makesound)
    {
        animal->table->makesound(animal);
    }
}

int main()
{

    Animal* cat=CatCreate("小猫");
    Animal* dog=DogCreate("小狗");
    //统一调用接口
    AnimalMakesound(cat);
    AnimalMakesound(dog);
    free(cat);
    free(dog);
    return 0;

}

单例模式

所谓单例模式就是要确保一个类仅仅有一个实例,并且提供全局访问点。C++实现单例模式需要解决线程安全问题、内存泄漏、对象销毁等问题。

设计要点

1、私有构造函数(禁止外部new创建实例)

2、私有拷贝/赋值运算符

3、提供全局访问点(通常是静态方法)

4、线程安全(多线程环境下避免创建多个实例);

5、自动销毁(避免内存泄漏)

复制代码
class Singleton
{
    public:
    //禁用拷贝 和赋值
        Singleton(const Singleton&)=delete;
        Singleton& operator=(const Singleton&)=delete;

    //全局访问点 唯一返回值
        static Singleton& Getinstance()
        {
        //局部静态变量 线程安全初始化 程序结束自动销毁
            static Singleton instance;
            return instance;
        }
        //测试接口
        void showtest(const string& msg)
        {
            cout<<"[Singleton:]"<<msg<<endl;
        }
private:
        //私有构造函数 禁止外部创建实例
    Singleton(){

        cout<<"实例创建成功"<<endl;

    }
    ~Singleton(){
	    cout<<"销毁成功"<<endl;
    }

};

int main()
{

    Singleton& s1=Singleton::Getinstance();
    Singleton& s2=Singleton::Getinstance();

    s1.showtest("s1实例");
    s1.showtest("s1 s2都是同一个实例!");

    cout<<"s1地址:"<<&s1<<endl;
    cout<<"s2地址:"<<&s2<<endl;

}

归并排序

输入:nums=5,2,3,1

输出:1,2,3,5

图解归并

复制代码
class Solution {

     vector<int>tmp;

public:

    vector<int> MySort(vector<int>& arr) {

        // write code here

        tmp.resize(arr.size());

        merage(arr,0,arr.size()-1);

        return arr;

    }

    void merage(vector<int>& arr,int l,int r)
    {
        if(l>=r) return ;
        int mid=(l+r)>>1;
        //

        merage(arr,l,mid);

        merage(arr,mid+1,r);

        //合并

        int cur1=l,cur2=mid+1,i=0;

        while(cur1<=mid&&cur2<=r)

        {

            tmp[i++]=arr[cur1]<=arr[cur2]?arr[cur1++]:arr[cur2++];

        }

        //处理剩下没有遍历的

        while(cur1<=mid)    tmp[i++]=arr[cur1++];

        while(cur2<=r)      tmp[i++]=arr[cur2++];

  

        for(int i=l;i<=r;i++)

        {

            arr[i]=tmp[i-l];

        }

    }

};

智能指针

shared_ptr

复制代码
#pragma once

#include<atomic>
using namespace std;

template<typename T>
class sharedPtr
{
private:
	T* ptr;
	atomic<size_t>* ref_count;

	void release()
	{
		if (ref_count && ref_count->fetch_sub(1)==1)
		{
			delete ptr;
			delete ref_count;
		}
	}
public:
	//默认构造
	sharedPtr():ptr(nullptr),ref_count(nullptr)
	{}
	//构造 防止隐式类型强转化
	explicit sharedPtr(T* p):ptr(p), ref_count(p?new atomic<size_t>(1):nullptr)
	{
			
	}

	//析构
	~sharedPtr()
	{ }
	//拷贝构造
	sharedPtr(const sharedPtr<T>& other) :ptr(other.ptr), ref_count(other.ref_count)
	{
        if(ref_count)
        {
            ref_count->fetch_add(1,memory_order_relaxed);
        }
	}

    //拷贝赋值
	sharedPtr<T>& operator=(const sharedPtr<T>& other)
	{
		if (this != other)
		{
			ptr = other.ptr;
			ref_count = other.ref_count;
			if (ref_count)
			{
				ref_count->fetch_add(1,memory_order_relaxed);
			}

		}
        return *this;
	}
    //移动构造 
    sharedPtr(sharedPtr<T>&& other)noexcept:ptr(other.ptr),ref_count(other.ref_count)
    {
        ptr=other.ptr;
        ref_count=other.ref_count;
    }
    //移动赋值 noexcept不会抛异常
    sharedPtr<T>& operator=(const sharedPtr<T>& other)noexcept
    {
        if(this!=&other)
        {
            release();
            ptr=other.ptr;
            ref_count=other.ref_count;
            other.ptr=nullptr;
            other.ref_count=nullptr;
        }
        return *this;
    }

    T& operator*()const{
        return *ptr;
    }
    T* operator->()const{
        return ptr;
    }

    //获取引用计算
    size_t use_count()const
    {
        return ref_count?ref_count->load(memory_order_acquire);
    }
    T* get()const{
        return ptr;
    }
    //重置指针
    void reset(T* p=nullptr)
    {
        release();
        ptr=p;
        ref_count=p? new atomic<size_t>(1):nullptr;
        
    }
};

链表oj(排序链表)

原题

链表的中间节点 合并两个有序链表(双指针),如果快指针指向空或者快指针下一节点指向空那么慢指针就在中间节点。ps:(因为这里我们需要找到中间节点并断开)

找到链表中间节点head1的前一个结点,并断开head1与前一个结点的连接。这样就把链表分成俩部分。分治递归调用sortlist函数。分别排序head(只有前一段)和head1.排序后得到两个有序链表,然后合并,得到排序后的链表,链表返回头节点。

复制代码
class Solution {

    //中间节点

    ListNode* middleSort(ListNode* head)

    {

        ListNode* pre=nullptr;

        ListNode* fast=head,*slow=head;

        while(fast&&fast->next)

        {

            pre=slow;

            slow=slow->next;

            fast=fast->next->next;

        }

        pre->next=nullptr;

        return slow;

    }

  

    //合并两个有序链表

    ListNode* mergeTwo(ListNode* l1,ListNode* l2)

    {

        ListNode dummy;

        ListNode* cur=&dummy;

        while(l1&&l2)

        {

            if(l1->val<l2->val)

            {

                cur->next=l1;

                l1=l1->next;//向后移动

            }

            else

            {

                cur->next=l2;

                l2=l2->next;

            }

            cur=cur->next;

        }

        //拼接剩余的链表

        cur->next=l1?l1:l2;

        return dummy.next;

    }

  

public:

    ListNode* sortList(ListNode* head) {

        if(head==nullptr||head->next==nullptr)

        {

            return head;

        }

        ListNode dummy;

        ListNode* head1=middleSort(head);//找到中间链表

  

        //分治

        head1=sortList(head1);

        head=sortList(head);

  

        return mergeTwo(head1,head);

  

    }

};

反转链表

输入一个链表,反转链表后,输出新链表的表头

详解:

1、因为链表结尾时null,pre是null,p指向头部

2、p的next成员马上要指向pre,不保存p的下一节点就会使其丢失,所以让t来存储它。

3、

复制代码
class Solution {
public:
    ListNode* ReverseList(ListNode* head) {
        // write code here
        ListNode* newnode=nullptr;
        while(head)
        {
            ListNode* nxt=head->next;
            head->next=newnode;
            newnode=head;
            head=nxt;

        }
        return newnode;
    }
};
相关推荐
雨师@1 小时前
go语言项目--实例化(图书管理)--005
开发语言·后端·golang
Aspiresky1 小时前
探索Rust语言之引用
开发语言·后端·rust
天空'之城2 小时前
Linux 系统编程 10:线程同步
linux·开发语言·系统编程·线程同步
Vect__2 小时前
Go 数据结构 slice 深度剖析
开发语言·数据结构·golang
想你依然心痛2 小时前
AtomCode在Python数据科学项目中的使用体验:从数据分析到可视化
开发语言·python·数据分析
我是个假程序员2 小时前
实例化动作脚本类,并执行,执行类似N_F1_SAVE.java这种
java·nc
满天星83035772 小时前
【Qt】控件(二) (geometry及与frameGeometry的区别)
开发语言·qt
aichitang20242 小时前
数论变换(NTT)
c++·算法·fft·ntt
wabil2 小时前
【LVGL】滑动切换页面的界面优化实践
开发语言·ios·swift