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