牛客网 SQL36查找后排序

SQL36查找后排序

sql 复制代码
select device_id,age from user_profile order by age asc
#select [字段1,字段2] from [表名] order by [字段1] [升序(asc)/降序(desc)],[字段2] [升序(asc)/降序(desc)]
#select:查询
#order by 排序

每日问题

如何实现对象的克隆?

在 C++ 中,实现对象的克隆通常涉及到复制对象的状态,以便创建一个新的对象,其内容与原始对象相同。克隆通常是通过深拷贝来实现的,特别是当对象包含动态分配的内存或资源时,使用浅拷贝可能导致资源共享和潜在的问题(如双重删除)。下面是实现对象克隆的一些常见方式。

1. 通过拷贝构造函数实现克隆

拷贝构造函数是用来创建一个对象,该对象是另一个对象的副本。默认情况下,拷贝构造函数执行浅拷贝,即复制对象的成员变量。但对于需要深拷贝的类(例如,包含动态内存分配的类),需要自己实现拷贝构造函数。

示例:

cpp 复制代码
#include <iostream>
#include <cstring>  // for strcpy

class Person {
public:
    char* name;
    int age;

    // 构造函数
    Person(const char* n, int a) {
        name = new char[strlen(n) + 1];
        strcpy(name, n);
        age = a;
    }

    // 拷贝构造函数:实现深拷贝
    Person(const Person& other) {
        name = new char[strlen(other.name) + 1];
        strcpy(name, other.name);
        age = other.age;
    }

    // 析构函数
    ~Person() {
        delete[] name;
    }

    // 打印函数
    void print() const {
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

int main() {
    Person p1("John", 30);  // 创建一个对象
    Person p2 = p1;  // 使用拷贝构造函数克隆 p1

    p1.print();
    p2.print();

    return 0;
}

输出:

cpp 复制代码
Name: John, Age: 30
Name: John, Age: 30

在这个例子中,Person 类有一个拷贝构造函数,它深拷贝了对象的 name 字符串和 age 整数。new 操作符确保了 name 字符串的深拷贝,避免了浅拷贝可能带来的资源共享问题。

2. 通过克隆接口实现克隆

如果你的类层次结构比较复杂,可能有一个基类,并且需要让派生类支持克隆操作,可以定义一个 clone() 方法。通常,clone() 方法返回一个指向新对象的指针,确保每个派生类都能正确实现其克隆。

为了实现这种方法,通常使用 虚函数 和 工厂方法。

示例:

cpp 复制代码
#include <iostream>
#include <cstring>

class Shape {
public:
    virtual ~Shape() = default;

    // 克隆接口
    virtual Shape* clone() const = 0;

    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    Circle(int r) : radius(r) {}

    // 克隆方法:实现圆形的深拷贝
    Shape* clone() const override {
        return new Circle(*this);  // 使用拷贝构造函数克隆
    }

    void draw() const override {
        std::cout << "Drawing a circle with radius " << radius << std::endl;
    }

private:
    int radius;
};

class Rectangle : public Shape {
public:
    Rectangle(int w, int h) : width(w), height(h) {}

    // 克隆方法:实现矩形的深拷贝
    Shape* clone() const override {
        return new Rectangle(*this);  // 使用拷贝构造函数克隆
    }

    void draw() const override {
        std::cout << "Drawing a rectangle with width " << width << " and height " << height << std::endl;
    }

private:
    int width, height;
};

int main() {
    Shape* circle = new Circle(5);
    Shape* rectangle = new Rectangle(10, 20);

    // 克隆对象
    Shape* clonedCircle = circle->clone();
    Shape* clonedRectangle = rectangle->clone();

    // 调用 draw 方法
    circle->draw();
    rectangle->draw();
    clonedCircle->draw();
    clonedRectangle->draw();

    // 释放内存
    delete circle;
    delete rectangle;
    delete clonedCircle;
    delete clonedRectangle;

    return 0;
}

输出:

cpp 复制代码
Drawing a circle with radius 5
Drawing a rectangle with width 10 and height 20
Drawing a circle with radius 5
Drawing a rectangle with width 10 and height 20

在这个例子中,我们创建了一个 Shape 基类,并在每个派生类(Circle 和 Rectangle)中实现了 clone() 方法。clone() 方法返回一个新创建的对象,确保每个派生类都能正确地进行深拷贝。

3. 使用 std::unique_ptr 或 std::shared_ptr 实现克隆

如果对象的管理使用智能指针,可以通过智能指针来管理对象的生命周期。在这种情况下,克隆通常会涉及到复制智能指针所管理的对象。

示例:

cpp 复制代码
#include <iostream>
#include <memory>  // for unique_ptr

class MyClass {
public:
    MyClass(int x) : data(x) {}
    MyClass(const MyClass& other) : data(other.data) {}  // 拷贝构造函数

    void print() const {
        std::cout << "Data: " << data << std::endl;
    }

private:
    int data;
};

int main() {
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(10);

    // 克隆 ptr1
    std::unique_ptr<MyClass> ptr2 = std::make_unique<MyClass>(*ptr1);

    ptr1->print();
    ptr2->print();

    return 0;
}

输出:

cpp 复制代码
Data: 10
Data: 10

在这个例子中,我们使用 std::unique_ptr 来管理 MyClass 的对象。在克隆时,我们通过 std::make_unique 和拷贝构造函数来创建新对象。

4. 通过工厂方法实现克隆

如果你希望将克隆操作与类的实例化分离,可以使用工厂方法来创建和克隆对象。这种方法特别适用于需要根据不同参数构造对象的情况。

示例:

cpp 复制代码
#include <iostream>

class Animal {
public:
    virtual ~Animal() = default;
    virtual Animal* clone() const = 0;
    virtual void speak() const = 0;
};

class Dog : public Animal {
public:
    Dog* clone() const override {
        return new Dog(*this);  // 使用拷贝构造函数克隆
    }

    void speak() const override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    Cat* clone() const override {
        return new Cat(*this);  // 使用拷贝构造函数克隆
    }

    void speak() const override {
        std::cout << "Meow!" << std::endl;
    }
};

int main() {
    Animal* dog = new Dog();
    Animal* cat = new Cat();

    // 克隆对象
    Animal* clonedDog = dog->clone();
    Animal* clonedCat = cat->clone();

    dog->speak();
    cat->speak();
    clonedDog->speak();
    clonedCat->speak();

    delete dog;
    delete cat;
    delete clonedDog;
    delete clonedCat;

    return 0;
}

输出:

cpp 复制代码
Woof!
Meow!
Woof!
Meow!

总结

在 C++ 中实现对象克隆的主要方法有:

1.通过拷贝构造函数实现克隆:适用于大多数简单的对象。需要自己编写拷贝构造函数,确保正确进行深拷贝。

2.通过克隆接口(clone() 方法)实现克隆:适用于有继承关系的类,能够让基类定义一个虚拟的 clone() 方法,派生类实现具体的克隆逻辑。

3.使用智能指针管理克隆:适用于使用智能指针(如 std::unique_ptr 或 std::shared_ptr)管理资源的对象,可以通过拷贝构造来克隆。

4.通过工厂方法实现克隆:通过一个专门的工厂方法来创建和克隆对象,适用于需要动态生成对象的情况。

如何实现单例模式?

在 C++ 中,单例模式(Singleton Pattern)是一种常用的设计模式,用于确保一个类只有一个实例,并且提供一个全局访问点来获取该实例。单例模式通常用于管理全局资源(如数据库连接、日志对象等),保证在应用程序的生命周期中只创建一个实例。

单例模式的关键特性:

1.私有构造函数:防止外部直接创建对象。

2.静态成员:用于存储类的唯一实例。

3.公有静态方法:提供访问该实例的方式。

单例模式的基本实现

cpp 复制代码
#include <iostream>

class Singleton {
private:
    // 私有构造函数,防止外部直接创建对象
    Singleton() {
        std::cout << "Singleton created!" << std::endl;
    }

    // 私有拷贝构造函数和赋值运算符,防止复制对象
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 提供获取实例的静态方法
    static Singleton& getInstance() {
        static Singleton instance;  // 局部静态变量,保证实例只创建一次
        return instance;
    }

    void showMessage() const {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

int main() {
    // 获取单例实例并调用方法
    Singleton& singleton1 = Singleton::getInstance();
    singleton1.showMessage();

    // 再次获取单例实例并调用方法
    Singleton& singleton2 = Singleton::getInstance();
    singleton2.showMessage();

    // 检查两个实例是否是同一个
    if (&singleton1 == &singleton2) {
        std::cout << "Both instances are the same." << std::endl;
    } else {
        std::cout << "Instances are different." << std::endl;
    }

    return 0;
}
解释:

1.私有构造函数:构造函数是私有的,这样外部代码无法直接创建 Singleton 对象。

2.静态 getInstance() 方法:getInstance() 方法是唯一可以获取 Singleton 实例的入口。它返回 Singleton 类的一个静态局部实例,这样确保实例只有一个,并且在第一次调用时创建。C++ 中的静态局部变量会在第一次访问时初始化,并且在程序结束时自动销毁。

3.禁止拷贝和赋值:通过删除拷贝构造函数和赋值运算符,防止对象被复制。

线程安全的实现(C++11及以上)

上面的实现是线程安全的,因为局部静态变量在 C++11 中是线程安全的。在 C++11 标准中,局部静态变量的初始化是线程安全的,即使多个线程同时访问 getInstance(),也不会创建多个实例。

单例模式的变种:懒汉式与饿汉式

懒汉式:实例在第一次使用时创建。需要考虑线程安全。

饿汉式:在程序启动时就创建实例,不管是否需要。简单且线程安全,但如果实例的创建成本较高,可能会浪费资源。

1. 懒汉式实现(线程安全)
cpp 复制代码
#include <iostream>
#include <mutex>

class Singleton {
private:
    Singleton() {
        std::cout << "Singleton created!" << std::endl;
    }

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static std::mutex mutex;  // 保护实例的互斥锁

public:
    static Singleton* getInstance() {
        static Singleton* instance = nullptr;

        // 双重检查锁定,确保线程安全且避免不必要的加锁
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mutex);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void showMessage() const {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

std::mutex Singleton::mutex;  // 初始化静态成员 mutex

int main() {
    Singleton* singleton1 = Singleton::getInstance();
    singleton1->showMessage();

    Singleton* singleton2 = Singleton::getInstance();
    singleton2->showMessage();

    if (singleton1 == singleton2) {
        std::cout << "Both instances are the same." << std::endl;
    }

    return 0;
}
解释:

1.懒汉式实现:实例只有在第一次访问时才会被创建(即 "懒加载")。使用 std::mutex 来保护实例的创建,以确保在多线程环境中只有一个实例。

2.双重检查锁定:通过 if (instance == nullptr) 进行第一次检查,如果仍然是 nullptr,才加锁创建实例。这样避免了每次获取实例时都加锁,提高了性能。

2. 饿汉式实现
cpp 复制代码
#include <iostream>

class Singleton {
private:
    // 私有构造函数
    Singleton() {
        std::cout << "Singleton created!" << std::endl;
    }

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static Singleton instance;  // 在程序启动时就创建实例

public:
    static Singleton& getInstance() {
        return instance;
    }

    void showMessage() const {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// 定义静态成员变量
Singleton Singleton::instance;

int main() {
    Singleton& singleton1 = Singleton::getInstance();
    singleton1.showMessage();

    Singleton& singleton2 = Singleton::getInstance();
    singleton2.showMessage();

    if (&singleton1 == &singleton2) {
        std::cout << "Both instances are the same." << std::endl;
    }

    return 0;
}
解释:

1.饿汉式实现:实例在程序启动时就被创建,并且是线程安全的,因为静态成员 instance 会在程序加载时初始化。

2.没有延迟创建:实例在程序启动时就创建,无论是否需要,可能会浪费资源。

总结

1.懒汉式(Lazy Initialization):

实例延迟创建,直到第一次访问时。

需要考虑线程安全,可以使用 std::mutex 或 C++11 中的线程安全局部静态变量。

优点:实例创建时机可控,节省资源。

缺点:需要额外的线程同步机制来保证线程安全。

2.饿汉式(Eager Initialization):

实例在程序启动时就创建。

简单且线程安全,但可能浪费资源,尤其是当实例创建代价较高时。

在大多数情况下,懒汉式更为灵活,尤其是当实例创建过程可能比较耗时或者实例未必每次都会使用时。使用静态局部变量的懒汉式在 C++11 及以上版本中非常推荐,它既是线程安全的,又实现了延迟加载。

相关推荐
贾修行1 分钟前
SQL Server 空间函数从入门到精通:原理、实战与多数据库性能对比
数据库·sqlserver
傲祥Ax13 分钟前
Redis总结
数据库·redis·redis重点总结
一屉大大大花卷1 小时前
初识Neo4j之入门介绍(一)
数据库·neo4j
叁沐1 小时前
MySQL 08 详解read view:事务到底是隔离的还是不隔离的?
mysql
周胡杰2 小时前
鸿蒙arkts使用关系型数据库,使用DB Browser for SQLite连接和查看数据库数据?使用TaskPool进行频繁数据库操作
前端·数据库·华为·harmonyos·鸿蒙·鸿蒙系统
wkj0012 小时前
navicate如何设置数据库引擎
数据库·mysql
ladymorgana2 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
赵渝强老师2 小时前
【赵渝强老师】Oracle RMAN的目录数据库
数据库·oracle
暖暖木头2 小时前
Oracle注释详解
数据库·oracle
御控工业物联网2 小时前
御控网关如何实现MQTT、MODBUS、OPCUA、SQL、HTTP之间协议转换
数据库·sql·http