SQL2 查询多列
sql">select device_id,gender,age,university from user_profile;
SQL3 查询结果去重
sql">select distinct university from user_profile;
select university from user_profile group by university;
C++ 中面向对象编程如何实现数据隐藏?
使用访问控制修饰符:
private 访问控制:
- 在类中,将数据成员声明为
private
,这是实现数据隐藏的最常见方式。private
成员只能在类的成员函数内部访问,外部代码(包括其他类和函数)无法直接访问这些成员。
protected 访问控制(用于继承场景):
protected
成员在类内部可访问,在派生类中也可以访问,但对于外部代码是不可访问的。它主要用于在继承层次结构中,允许派生类访问基类的部分成员,但仍然隐藏这些成员不让外部直接访问。
Pimpl模式:
定义:Pimpl模式是指pointer to implementation。也就是说将类Widget的实现完全放到另外一个类Impl里,而类Widget对外提供接口,这些接口的调用最终会通过Impl指针成员(裸指针或智能指针),调用相应的实现接口。
具体实现:在头文件中只有一个私有成员变量pimpl指针,用户无法直接从头文件获取信息,起到了数据信息隐藏的作用
book.h
#pragma once
#include <iostream>class impl;class book
{
public:book();book(std::string, double);~book();/*私有成员为指针,禁止使用C++默认浅拷贝*/book(const book&) = delete;book& operator=(const book&) = delete;//移动拷贝构造book(book&&);book& operator=(book&&);void display();
private:std::unique_ptr<impl> pImpl;
};
book.cpp
#include "book.h"class impl
{
public:impl() {}impl(std::string name, double price);~impl();void display();void set_price(double);double get_price();
private:std::string book_name;double book_price;
};impl::impl(std::string name, double price) :book_name(name), book_price(price)
{}impl::~impl()
{}void impl::display()
{std::cout << "book name:" << book_name << std::endl;std::cout << "book price:" << book_price << std::endl;
}void impl::set_price(double price)
{book_price = price;
}double
impl::get_price()
{return book_price;
}book::book() :pImpl(std::make_unique<impl>())
{}book::book(std::string name, double price) : pImpl{ std::make_unique<impl>(name,price) }
{}book::~book() = default;book& book::operator=(book&&) = default;void book::display()
{pImpl->display();
}
main.cpp
#include "book.h"int main()
{book b("百年孤独", 100);b.display();
}
运行结果
优势:这么做可以减少项目的依赖,进而减少不必要的编译。无法从头文件获取类的具体实现。
缺点:会在运行时增加开销,访问开销(对私有成员的每次访问都是用过指针间接访问的)、空间开销、生命周期管理开销,降低程序可读性。
C++ 中面向对象编程如何处理异常?
try - catch 块:
- C++ 使用
try - catch
块来捕获和处理异常。try
块中放置可能会抛出异常的代码。当异常被抛出时,程序的控制权会转移到相应的catch
块中。
try {// 可能抛出异常的代码int dividend = 10;int divisor = 0;int result = dividend / divisor;} catch (const std::runtime_error& e) {// 处理runtime_error类型的异常std::cerr << "Runtime error: " << e.what() << std::endl;} catch (const std::exception& e) {// 处理其他类型的exception异常std::cerr << "General exception: " << e.what() << std::endl;} catch (...) {// 捕获所有其他类型的异常std::cerr << "An unknown exception occurred." << std::endl;}
- 在这个例子中,尝试进行除法运算,当除数为 0 时,会抛出一个异常。
try - catch
块会捕获这个异常并进行相应的处理。 - 异常类和层次结构:
- C++ 标准库提供了一系列的异常类,如
std::exception
是所有标准异常类的基类。它有许多派生类,如std::runtime_error
、std::logic_error
等。 - 可以自定义异常类,通过继承
std::exception
或其子类来实现。例如:
- C++ 标准库提供了一系列的异常类,如
class MyException : public std::runtime_error {public:MyException(const char* msg) : runtime_error(msg) {}};
- 然后在代码中抛出和捕获这个自定义异常:
try {// 假设某个条件触发异常抛出throw MyException("This is my custom exception.");} catch (const MyException& e) {std::cerr << "Caught my custom exception: " << e.what() << std::endl;}
- 异常安全保证:
- 基本的异常安全保证包括:
- 基本保证:如果异常被抛出,程序中的对象仍然保持在一个合理的状态。例如,在一个函数中,如果部分操作失败并抛出异常,对象不会处于一个被破坏的、无法使用的状态。
- 强保证:函数要么完全成功,要么在抛出异常时将程序状态恢复到调用该函数之前的状态。这通常通过使用资源获取即初始化(RAII)技术来实现。例如,在构造函数中分配资源,如果构造失败,资源会被自动释放。
- 不抛出保证(Nothrow guarantee):某些函数被保证不会抛出异常,例如一些简单的访问器函数(如
get
函数)可以设计为不抛出异常,以提供更可靠的行为。
- 基本的异常安全保证包括: