C++ 常用基础

Talk is cheap,show the code
及时更新

多态

静态多态(编译时多态):

  • 函数重载(Function Overloading):
    实现原理:在同一作用域内,根据函数的参数列表(参数类型、参数个数或参数顺序)的不同,定义多个同名函数,编译器在编译时根据调用时的实参来决定调用哪个函数。
#include <iostream>
class Math {
   
public:
    int add(int a, int b) {
   
        return a + b;
    }
    double add(double a, double b) {
   
        return a + b;
    }
};
int main() {
   
    Math m;
    std::cout << m.add(1, 2) << std::endl;
    std::cout << m.add(1.0, 2.0) << std::endl;
    return 0;
}

在上述代码中,Math类中定义了两个名为add的函数,它们的参数类型不同,一个是int类型,一个是double类型。当调用add函数时,编译器会根据传入的实参类型决定调用哪个add函数。

  • 运算符重载(Operator Overloading):
    实现原理:通过重载运算符函数,改变运算符的默认行为,使其可以操作自定义类型。运算符重载函数可以是类的成员函数或全局函数。
#include <iostream>
class Complex {
   
private:
    double real;
    double imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {
   }
    Complex operator+(const Complex& c) const {
   
        return Complex(real + c.real, imag + c.imag);
    }
};
int main() {
   
    Complex c1(1.0, 2.0);
    Complex c2(3.0, 4.0);
    Complex c3 = c1 + c2;
    return 0;
}

在Complex类中重载了+运算符,使其可以对Complex对象进行相加操作。当使用c1 + c2时,会调用operator+函数。

动态多态(运行时多态):

  • 虚函数(Virtual Functions)和覆盖(Overriding):
    当一个类中定义了虚函数,编译器会为该类创建一个虚函数表(VTable),其中存储了该类的虚函数的地址。
    每个包含虚函数的类的对象都包含一个虚函数指针(vptr),该指针指向该类的虚函数表。
    当通过基类指针或引用调用虚函数时,程序会根据对象的实际类型,在运行时通过虚函数指针找到对应的虚函数表,并调用相应的虚函数。
#include <iostream>
class Shape {
   
public:
    virtual void draw() {
   
        std::cout << "Drawing a shape." << std::endl;
    }
};
class Circle : public Shape {
   
public:
    void draw() override {
   
        std::cout << "Drawing a circle." << std::endl;
    }
};
int main() {
   
    Shape* shapePtr = new Circle();
    shapePtr->draw();
    delete shapePtr;
    return 0;
}

Shape类中定义了虚函数draw,Circle类继承自Shape并覆盖了draw函数。
当使用Shape* shapePtr = new Circle();创建一个Circle对象并使用Shape指针指向它,然后调用draw函数时,由于draw是虚函数,程序会在运行时根据shapePtr所指向对象的实际类型(Circle)调用Circle类的draw函数。

虚基类

在多重继承中,当一个派生类从多个基类继承,而这些基类又有共同的父类时,会出现二义性问题,即派生类会继承多个共同父类的副本。虚基类就是为了解决这个问题而引入的,它确保在派生类中只存在一个共同基类的副本。
定义方式:
在继承时使用 virtual 关键字将共同的基类声明为虚基类。

#include <iostream>

class Base {
   
public:
    int value;
    Base() : value(0) {
    std::cout << "Base Constructor" << std::endl; }
};


class Derived1 : virtual public Base {
   
public:
    Derived1() {
    std::cout << "Derived1 Constructor" << std::endl; }
};


class Derived2 : virtual public Base {
   
public:
    Derived2() {
    std::cout << "Derived2 Constructor" << std::endl; }
};


class FinalDerived : public Derived1, public Derived2 {
   
public:
    FinalDerived() {
    std::cout << "FinalDerived Constructor" << std::endl; }
};


int main() {
   
    FinalDerived obj;
    // 不会产生二义性,因为 Base 只有一个副本
    obj.value = 10; 
    return 0;
}

线程锁的种类:互斥锁,条件锁,自旋锁,读写锁,递归锁

互斥锁

互斥锁是最基本的线程锁,用于保护共享资源,确保同一时间只有一个线程可以访问该资源。
当一个线程获取互斥锁后,其他线程尝试获取该锁时会被阻塞,直到锁被释放。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void printMessage(const std::string& message) {
   
    std::lock_guard<std::mutex> lock(mtx);  // 使用 lock_guard 自动管理锁的获取和释放
    std::cout << message << std::endl;
}

int main() {
   
    std::thread t1(printMessage, "Hello from thread 1");
    std::thread t2(printMessage, "Hello from thread 2");
    t1.join();
    t2.join();
    return 0;
}

条件锁

条件锁通常与互斥锁一起使用,允许线程等待某些条件的发生。
线程可以在条件不满足时进入等待状态,当条件满足时,其他线程可以通知等待的线程继续执行。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;

void producer() {
   
    for (int i = 0; i < 10; ++i) {
   
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        std::unique_lock<std::mutex> lock(mtx);
        data_queue.push(i);
        std::cout << "Produced: " << i << std::endl;
        cv.notify_one();  // 通知一个等待的线程
    }
}

void consumer() {
   
    while (true) {
   
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, []{
    return!data_queue.empty(); });  // 等待直到队列不为空
        int data = data_queue.front();
        data_queue.pop();
        lock.unlock();
        std::cout << "Consumed: " << data << std::endl;
        if (data == 9) break;
    }
}

int main() {
   
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}

自旋锁

自旋锁不会使线程进入睡眠状态,而是在获取锁时循环等待,不断检查锁是否可用。
适用于锁的持有时间很短的情况,因为自旋锁不涉及线程的上下文切换。

#include <iostream>
#include <thread>
#include <atomic>

std::atomic_flag lock = ATOMIC_FLAG_INIT;

void printMessage(const std::string& message) {
   
    while (lock.test_and_set(std::memory_order_acquire)) {
   
        // 自旋等待
    }
    std::cout << message << std::endl;
    lock.clear(std::memory_order_release);
}

int main() {
   
    std::thread t1(printMessage, "Hello from thread 1");
    std::thread t2(printMessage, "Hello from thread 2");
    t1.join();
    t2.join();
    return 0;
}

读写锁(Read-Write Lock)

读写锁允许多个线程同时读共享资源,但写操作是独占的。
当有线程进行写操作时,其他线程的读和写操作都被阻塞;当有线程进行读操作时,其他线程可以继续读,但写操作被阻塞。

#include <iostream>
#include <thread>
#include <shared_mutex>

std::shared_mutex rwMutex;

void readData() {
   
    std::shared_lock<std::shared_mutex> lock(rwMutex);  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值