这是一篇C++复习笔记。参考力扣上的收费教程 C++ 面试突破 整理而成【侵删】,根据我的理解对部分内容做了删减和调整,比如删掉了c++20等比较新的内容(暂时还用不到),过滤了比较老的C++语法,重难点增加了自己的理解。每段代码我都自己调试过,除了编译器导致的差异,基本没问题。
想读完整的原版内容,请移步力扣官网C++ 面试突破
// x 是左值,666 为右值
int x = 666; // ok
int *y = x; // ok
int *z = &666 // error
666 = x; // error
int a = 9; // a 为左值
int b = 4; // b 为左值
int c = a + b // c 为左值 , a + b 为右值
a + b = 42; // error
万能模板
万能模板既可以接受左值作为实参也可以接受右值作为实参
std::move 原理
move代码:
template
typename remove_reference::type&& move(T&& t)
{
return static_cast::type &&>(t);
}
remove_reference实现
//原始的,最通用的版本
template struct remove_reference{
typedef T type; //定义 T 的类型别名为 type
};
//部分版本特例化,将用于左值引用和右值引用
template struct remove_reference //左值引用
{ typedef T type; }
template struct remove_reference //右值引用
{ typedef T type; }
//举例如下,下列定义的a、b、c三个变量都是int类型
int i;
remove_refrence::type a; //使用原版本,
remove_refrence::type b; //左值引用特例版本
remove_refrence::type b; //右值引用特例版本
#include
using namespace std;
template
void fun(T&& tmp)
{
cout << "fun rvalue bind:" << tmp << endl;
}
template
void fun(T& tmp)
{
cout << "fun lvalue bind:" << tmp << endl;
}
template
void test(T&& x) {
fun(x); // 10为右值,调用fun(x)时,变成了左值
fun(std::forward(x));
}
int main()
{
int a = 10;
test(10);
test(a);
return 0;
}
/*
fun lvalue bind:10
fun rvalue bind:10
fun lvalue bind:10
fun lvalue bind:10
*/
仔细体会下上面的代码,调用test(10),test函数知道x为右值,但是调用fun(x)时,x已经成了左值。通过std::forward(x) 强行在x前面再加上&或者&&,以匹配对应的模板函数。
和move的区别是
指针的基本概念比较好理解,函数指针稍微复杂点,重点提下:
#include
using namespace std;
int add(int a, int b){
return a + b;
}
typedef int (*fun_p)(int, int);
int main(void)
{
fun_p fn = add;
cout << fn(1, 6) << endl;
return 0;
}
定义指向成员函数的指针时,要标明指针所属的类。
#include
using namespace std;
class A
{
public:
int var1, var2;
static int x;
static int get() {
return 100;
}
int add(){
return var1 + var2;
}
};
int main()
{
A ex;
ex.var1 = 3;
ex.var2 = 4;
int *p = &ex.var1; // 指向对象成员变量的指针
cout << *p << endl;
int (A::*fun_p)();
int (*fun_q)();
fun_p = &A::add; // 指向对象非静态成员函数的指针 fun_p
fun_q = A::get; // 指向对象静态成员函数的指针 fun_q
cout << (ex.*fun_p)() << endl;
cout << (*fun_q)() << endl;
return 0;
}
全局函数、类函数、类静态成员函数的指针均有点不一样,没有深究,或许c++编译器就这么定义的。
#include
using namespace std;
int fun1(int tmp1, int tmp2)
{
return tmp1 * tmp2;
}
int fun2(int tmp1, int tmp2)
{
return tmp1 / tmp2;
}
int main()
{
int (*fun)(int x, int y);
fun = fun1; // ok
fun = &fun1; // ok 两种写法均可以
cout << fun(15, 5) << endl;
fun = fun2;
cout << fun(15, 5) << endl;
cout<
void *p = malloc(size);
free(p); // 此时,p 指向的内存空间已释放, p 就是悬空指针。
p = NULL;
void *p;
// 此时 p 是“野指针”。
const_cast
主要用于 const -> 非const; volatile -> 非volatile转换,是单向的,反之不行,即只能作用于常量,将常量、常量指针变成非常量、非常量指针
reinterpret_cast
改变指针或引用的类型
即子类对象可用父类指针指引,基类对象不能用子类指引,因为基类可能没有子类的方法,子类指针调用的函数可能不存在会crash
看个例子,基类转子类的两种情况,一种成功,一种失败
#include
#include
using namespace std;
class Base
{
public:
virtual void fun()
{
cout << "Base::fun()" << endl;
}
};
class Derive : public Base
{
public:
virtual void fun()
{
cout << "Derive::fun()" << endl;
}
};
int main()
{
Base *p1 = new Derive();
Base *p2 = new Base();
Derive *p3 = new Derive();
//转换成功
p3 = dynamic_cast(p1);
if (p3 == NULL)
{
cout << "NULL" << endl;
}
else
{
cout << "NOT NULL" << endl; // 输出
}
//转换失败
p3 = dynamic_cast(p2);
if (p3 == NULL)
{
cout << "NULL" << endl; // 输出
}
else
{
cout << "NOT NULL" << endl;
}
return 0;
}
参考std::move中用到的remove_reference函数,里面typedef _Tp type就是萃取。在编译器获取了模板参数_Tp的类型
/// remove_reference
template
struct remove_reference
{ typedef _Tp type; };
template
struct remove_reference<_Tp&>
{ typedef _Tp type; };
template
struct remove_reference < _Tp&& >
{ typedef _Tp type; };
需要重载操作符 == 判断两个结构体是否相等,不能用函数 memcmp 来判断两个结构体是否相等,因为 memcmp 函数是逐个字节进行比较的,而结构体存在内存空间中保存时存在字节对齐,字节对齐时补的字节内容是随机的,会产生垃圾值,所以无法比较。
#include
using namespace std;
struct A
{
char c;
int val;
A(char c_tmp, int tmp) : c(c_tmp), val(tmp) {}
friend bool operator==(const A &tmp1, const A &tmp2); // 友元运算符重载函数
};
bool operator==(const A &tmp1, const A &tmp2)
{
return (tmp1.c == tmp2.c && tmp1.val == tmp2.val);
}
int main()
{
A ex1('a', 90), ex2('b', 80);
if (ex1 == ex2)
cout << "ex1 == ex2" << endl;
else
cout << "ex1 != ex2" << endl; // 输出
return 0;
}
不用友元也可以,结构体的函数是public的
struct A {
char c;
int val;
A(char c_tmp, int tmp) : c(c_tmp), val(tmp) {}
bool operator==(const A &tmp2) {
return c == tmp2.c && val == tmp2.val;
};
};
函数模板调用方式举例:
#include
using namespace std;
template
T add_fun(const T & tmp1, const T & tmp2){
return tmp1 + tmp2;
}
int main(){
int var1, var2;
cin >> var1 >> var2;
cout << add_fun(var1, var2); // 显式调用
double var3, var4;
cin >> var3 >> var4;
cout << add_fun(var3, var4); // 隐式调用
return 0;
}
定义函数模板的特化版本,本质上是接管了编译器的工作,为原函数模板定义了一个特殊实例
#include
#include
using namespace std;
//函数模板
template
bool compare(T t1, T t2)
{
cout << "通用版本:";
return t1 == t2;
}
template <> //函数模板特化
bool compare(char *t1, char *t2)
{
cout << "特化版本:";
return strcmp(t1, t2) == 0;
}
int main(int argc, char *argv[])
{
char arr1[] = "hello";
char arr2[] = "abc";
cout << compare(123, 123) << endl;
cout << compare(arr1, arr2) << endl;
return 0;
}
/*
运行结果:
通用版本:1
特化版本:0
*/
可变参数函数通常是递归的,第一个版本的 print_fun 负责终止递归并打印初始调用中的最后一个实参。第二个版本的 print_fun 是可变参数版本,打印绑定到 t 的实参,并用来调用自身来打印函数参数包中的剩余值。
#include
using namespace std;
template
void print_fun(const T &t)
{
cout << t << endl; // 最后一个元素
}
template
void print_fun(const T &t, const Args &...args)
{
cout << t << " ";
print_fun(args...);
}
int main()
{
print_fun("Hello", "world", "!");
return 0;
}
/*运行结果:
Hello wolrd !
*/
std::thread t([](){
std::cout << "hello world." << std::endl;
});
t.join();
std::mutex mtx;
std::lock_guard lock(mtx);
如果对c++多线程不了解,可以先看看我之前写的一篇入门文章,《C++ 多线程入门》
https://mp.weixin.qq.com/s/b1HhzqBkt7mxo9v7pQJZHg
std::unique_lock lock(mtx);
std::condition_variable cv:
cv.wait(lock); // cv必须指定,你等的是哪一把锁啊,不然咋知道你和哪个线程争夺执行权呢
std::this_thread::sleep_for(std::chrono::seconds(1));
#include
#include
#include
#include
#include
using namespace std::chrono_literals;
std::condition_variable cv; // 条件变量 wait
std::mutex cv_m; //原始互斥量 lock
int i;
void waits(int idx)
{
std::unique_lock lk(cv_m);
// wait_for(lock, 超时duration, Predicate)
// Predicate有函数调用功能即可,作为唤醒时附加的判断条件,predicate成立才能真的唤醒,重新获得锁和执行权,此处判断i==1
// 这里有三个线程调用,分别等待100ms,200ms,300ms
if (cv.wait_for(lk, idx*100ms, []{return i == 1;})) {
std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
} else {
std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}
}
void signals()
{
// 等120ms,让第一个线程等100ms超时,看看超时的效果
std::this_thread::sleep_for(120ms);
std::cerr << "Notifying...\n";
// 唤醒,第二个、三个线程分别唤醒后 predicate不满足,又继续睡了
// 好比你妈把你喊醒,叫你上学,你醒了一看才5点,不到6点。又继续睡了
cv.notify_all(); // 唤醒所有cv.wait
// 当前线程sleep,一共sleep220ms了
// 此时第二个线程等了200ms,没人叫他,自己超时醒了
std::this_thread::sleep_for(100ms);
{
// 注意这是在代码块里面,lock_guard出了代码块会unlock
std::lock_guard lk(cv_m);
i = 1; //修改i == 1,让第三个线程能predicate成功
}
std::cerr << "Notifying again...\n";
// 第二次唤醒,第一个、第二个线程已经超时了,第三个线程唤醒了,而且i == 1,那就真的醒了
cv.notify_all();
}
int main()
{
std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
t1.join(); // t1 等待 100ms 后未被唤醒,自动超时;
t2.join(); // t2 在 120 ms 处被唤醒,但 condition 未满足,再此进入阻塞,200ms 时由于超时返回
t3.join(); // t3 在 120 ms 处被唤醒,但 condition 未满足,再此进入阻塞,220ms 时被 notify ,正常返回。
t4.join();
}
/*
Thread 1 timed out. i == 0
Notifying...
Thread 2 timed out. i == 0
Notifying again...
Thread 3 finished waiting. i == " 1
*/
例2 notify_one notify_all
注意,门开锁了,也得一个个出去,即一个线程执行完了,释放锁了,其他的线程才能接着获得线程执行权跟着出门。简言之,notify_one最终只有一个等待线程激活,notify_all最终会激活所有等待线程。
notify_one
// condition_variable::notify_one
#include // std::cout
#include // std::thread
#include // std::mutex, std::unique_lock
#include // std::condition_variable
std::mutex mtx;
std::condition_variable produce,consume;
int cargo = 0; // shared value by producers and consumers
void consumer () {
std::unique_lock lck(mtx);
while (cargo==0) consume.wait(lck);
std::cout << cargo << '\n';
cargo=0;
produce.notify_one();
}
void producer (int id) {
std::unique_lock lck(mtx);
while (cargo!=0) produce.wait(lck);
cargo = id;
consume.notify_one();
}
int main ()
{
std::thread consumers[10],producers[10];
// spawn 10 consumers and 10 producers:
for (int i=0; i<10; ++i) {
consumers[i] = std::thread(consumer);
producers[i] = std::thread(producer,i+1);
}
// join them back:
for (int i=0; i<10; ++i) {
producers[i].join();
consumers[i].join();
}
return 0;
}
notify_all
#include
#include
#include
#include
std::condition_variable_any cv;
std::mutex cv_m; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits(int idx)
{
std::unique_lock lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cerr << "thread:"<< idx <<" ...finished waiting. i == 1\n";
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard lk(cv_m);
std::cerr << "Notifying...\n";
}
cv.notify_all();
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard lk(cv_m);
i = 1;
std::cerr << "Notifying again...\n";
}
cv.notify_all();
}
int main()
{
std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
t1.join();
t2.join();
t3.join();
t4.join();
}
举例说明假唤醒:生产者-消费者模型下,消费者有3个线程处于wait
实际工程中涉及的共享数据和流程比较复杂,很容易出现异常。所以此时最好的办法就是,判断面包还在吗?不在的话我接着睡吧,别起来捣乱了。
lock(mutex);
while( !面包还在吗) { // 注意"!"否定
// 面包不在了
condition_wait( cond, mutex);
}
// 面包还在,退出while循环,起来吃面包了
do(something);
// 吃完面包,释放锁
unlock(mutex);
mutex 比较简单,不再赘述。补充几个线程同步的知识点。
#include
#include
#include
std::mutex mtx;
void print_block (int n, char c) {
mtx.lock();
for (int i=0; i
std::recursive_mutex mtx;
void fun1() {
mtx.lock();
mtx.unlock();
}
void fun2() {
mtx.lock();
fun1(); // recursive lock
mtx.unlock();
};
实现场景:多个线程同时读,只有一个线程能写入
#include
#include // For std::unique_lock
#include
#include
class ThreadSafeCounter {
public:
ThreadSafeCounter() = default;
// 多个线程可以同时读取 countter 计数
unsigned int get() const {
std::shared_lock lock(mutex_);
return value_;
}
// 只有1个线程可以修改 countter 计数
void increment() {
std::unique_lock lock(mutex_);
value_++;
}
// 只有1个线程可以修改 countter 计数
void reset() {
std::unique_lock lock(mutex_);
value_ = 0;
}
private:
mutable std::shared_mutex mutex_;
unsigned int value_ = 0;
};
int main() {
ThreadSafeCounter counter;
auto increment_and_print = [&counter]() {
for (int i = 0; i < 3; i++) {
counter.increment();
std::cout << std::this_thread::get_id() << ' ' << counter.get() << '\n';
// Note: Writing to std::cout actually needs to be synchronized as well
// by another std::mutex. This has been omitted to keep the example small.
}
};
std::thread thread1(increment_and_print);
std::thread thread2(increment_and_print);
thread1.join();
thread2.join();
}
/*
139677317637888 2
139677317637888 3
139677309245184 4
139677309245184 5
139677309245184 6
139677317637888 6
*/
有些场景,比如仅触发一次,还挺有用的,避免冗余的判断逻辑。
#include
#include
#include
std::once_flag flag1, flag2;
void simple_do_once()
{
std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
int main()
{
std::thread st1(simple_do_once);
std::thread st2(simple_do_once);
std::thread st3(simple_do_once);
std::thread st4(simple_do_once);
st1.join();
st2.join();
st3.join();
st4.join();
}
/*
Simple example: called once
*/
### 线程高级用法
1. 成员函数异步调用另一个成员函数,需加上this参数
```c++
class Test{
private:
void func1(const std::string s1, int i) {
std::cout << s1 << std::endl;
}
public:
void func2() {
std::thread t1(&Test::func1, this, "test", 0);
t1.detach();
std::cout << "func2" << std::endl;
}
类成员函数默认会有个this参数,编译器帮我们干了,换了个线程,找不到this,所以要手动传进去
template
future::type> async(launch policy, Fn&& fn, Args&&...args);
看个简单的例子:
#include "pch.h"
#include
#include
#include
#include
#include
using namespace std::chrono;
std::string fetchDataFromDB(std::string recvData) {
std::cout << "fetchDataFromDB start" << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(seconds(5));
return "DB_" + recvData;
}
std::string fetchDataFromFile(std::string recvData) {
std::cout << "fetchDataFromFile start" << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(seconds(3));
return "File_" + recvData;
}
int main() {
std::cout << "main start" << std::this_thread::get_id() << std::endl;
//获取开始时间
system_clock::time_point start = system_clock::now();
std::future resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
//从文件获取数据
std::future fileData = std::async(std::launch::deferred, fetchDataFromFile, "Data");
//知道调用get函数fetchDataFromFile才开始执行
std::string FileData = fileData.get();
//如果fetchDataFromDB()执行没有完成,get会一直阻塞当前线程
std::string dbData = resultFromDB.get();
//获取结束时间
auto end = system_clock::now();
auto diff = duration_cast(end - start).count();
std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
//组装数据
std::string data = dbData + " :: " + FileData;
//输出组装的数据
std::cout << "Data = " << data << std::endl;
return 0;
}
可以通过查询 future 的状态(future_status)来获取异步操作的结果。future_status 有三种状态:
获取 future 结果有三种方式:
get
wait
wait_for
其中 get 等待异步操作结束并返回结果,wait 只是等待异步操作完成,没有返回值,wait_for 是超时等待返回结果
I/O放到任何语言可以说的话题都很多,这段只是简单提下。
所有流对象都有一个关联的数据成员类 streambuf,是流的缓冲区。
当我们从流中读取数据时,我们不会直接从源中读取数据,而是从链接到源的缓冲区中读取数据
C++ 允许我们为任何流设置流缓冲区,因此重定向流的任务简单地减少为更改与流关联的流缓冲区。
stream_object.rdbuf()://获取返回指向stream_object的流缓冲区的指针
stream_object.rdbuf(streambuf * p)://将流缓冲区设置为p指向的
// Cpp program to redirect cout to a file
#include
#include
#include
using namespace std;
int main()
{
fstream file;
file.open("cout.txt", ios::out);
string line;
// 保存 cin 和 cout 的缓冲区 buffer
streambuf* stream_buffer_cout = cout.rdbuf();
streambuf* stream_buffer_cin = cin.rdbuf();
// 获取文件 file 的缓冲区 buffer
streambuf* stream_buffer_file = file.rdbuf();
// cout 重定向文件,会生成一个cout.txt文件
cout.rdbuf(stream_buffer_file);
cout << "This line written to file" << endl;
// cout 恢复重定
cout.rdbuf(stream_buffer_cout);
cout << "This line is written to screen" << endl;
file.close();
return 0;
}
在各种情况下,可能需要清除不需要的缓冲区,以便在所需的程序中立即获取下一个输入
下面这个程序不能得到正确的效果,ch为空,因为\n保留在缓冲区,作为下一个输入读取
#include
#include
using namespace std;
int main()
{
int a;
char ch[80];
cin >> a;
cin.getline(ch,80);
cout << a << endl;
cout << ch << endl;
return 0;
}
有两种方法修改:
修改后:
#include
#include //used to get stream size
#include //used to get numeric limits
using namespace std;
int main()
{
int a;
char ch[80];
cin >> a;
cin.ignore(numeric_limits::max(),'\n'); //方法一
cint >> ws;// 方法二
cin.getline(ch,80);
cout << a << endl;
cout << ch << endl;
return 0;
}
实现思路:
class singleton {
private:
static singleton* instance;
singleton(const singleton& temp) {}
singleton& operator=(const singleton& temp){}
protected:
singleton() {}
public:
static singleton* getInstance() {
return instance;
}
}
// 类静态变量要在类内声明,类外初始化
// 初始化可以访问构造函数
singleton::instance = new singleton();
class Singleton{
private:
static Singleton* instance;
Singleton(const Singleton& temp) {}
Singleton& operator=(const Singleton& temp){}
Singleton() {}
public:
static Singleton* getInstance(){
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Singleton::instance = NULL;
class Singleton {
private:
static std::mutex mtx;
static Singleton* instance;
Singleton(){}
Singleton&(const Singleton& temp){}
Singleton& operator=(const Singleton& temp){}
public:
static Singleton* getInstance() {
mtx.lock();
if (instance == NULL) {
instance = new Singleton();
}
return instance;
mtx.unlock();
}
}
class Singleton{
private:
Singleton(){}
Singleton&(const Singleton& tmp){}
Singleton& operator=(const Singleton& tmp){}
public:
static Singleton* getInstance() {
static Singleton instance;
return &instance;
}
}
“简单工厂”、“工厂方法”、“抽象工厂”
下面以加减乘除的实现为例
#include
#include
using namespace std;
// Here is the product class
class Operation
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};
class Add_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};
class Sub_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};
class Mul_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};
class Div_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};
// Here is the Factory class
class Factory
{
public:
static Operation *CreateProduct(char op)
{
switch (op)
{
case '+':
return new Add_Operation();
case '-':
return new Sub_Operation();
case '*':
return new Mul_Operation();
case '/':
return new Div_Operation();
default:
return new Add_Operation();
}
}
};
int main()
{
int a, b;
cin >> a >> b;
Operation *p = Factory::CreateProduct('+');
p->var1 = a;
p->var2 = b;
cout << p->GetResult() << endl;
p = Factory::CreateProduct('*');
p->var1 = a;
p->var2 = b;
cout << p->GetResult() << endl;
return 0;
}
每个工厂对应一个一个类, 基于面向接口编程,所有的工厂都继承同一个工厂基类
#include
#include
using namespace std;
// Here is the product class
class Operation
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};
class Add_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};
class Sub_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};
class Mul_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};
class Div_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};
class Factory
{
public:
virtual Operation *CreateProduct() = 0;
};
class Add_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Add_Operation();
}
};
class Sub_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Sub_Operation();
}
};
class Mul_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Mul_Operation();
}
};
class Div_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Div_Operation();
}
};
int main()
{
int a, b;
cin >> a >> b;
Add_Factory *p_fac = new Add_Factory();
Operation *p_pro = p_fac->CreateProduct();
p_pro->var1 = a;
p_pro->var2 = b;
cout << p_pro->GetResult() << endl;
Mul_Factory *p_fac1 = new Mul_Factory();
Operation *p_pro1 = p_fac1->CreateProduct();
p_pro1->var1 = a;
p_pro1->var2 = b;
cout << p_pro1->GetResult() << endl;
return 0;
}
看起来感觉就多了一个产品大类
我之前学习李建忠设计模式里,将抽象工厂,以数据库为例,是非常复杂的,但是应对复杂项目,后期威力巨大。并不是这么简单的拓展一个接口即可。
#include
#include
using namespace std;
// Here is the product class
class Operation_Pos
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};
class Add_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};
class Sub_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};
class Mul_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};
class Div_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};
/*********************************************************************************/
class Operation_Neg
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};
class Add_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 + var2);
}
};
class Sub_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 - var2);
}
};
class Mul_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 * var2);
}
};
class Div_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 / var2);
}
};
/*****************************************************************************************************/
// Here is the Factory class
class Factory
{
public:
virtual Operation_Pos *CreateProduct_Pos() = 0;
virtual Operation_Neg *CreateProduct_Neg() = 0;
};
class Add_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Add_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Add_Operation_Neg();
}
};
class Sub_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Sub_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Sub_Operation_Neg();
}
};
class Mul_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Mul_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Mul_Operation_Neg();
}
};
class Div_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Div_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Div_Operation_Neg();
}
};
int main()
{
int a, b;
cin >> a >> b;
Add_Factory *p_fac = new Add_Factory();
Operation_Pos *p_pro = p_fac->CreateProduct_Pos();
p_pro->var1 = a;
p_pro->var2 = b;
cout << p_pro->GetResult() << endl;
Add_Factory *p_fac1 = new Add_Factory();
Operation_Neg *p_pro1 = p_fac1->CreateProduct_Neg();
p_pro1->var1 = a;
p_pro1->var2 = b;
cout << p_pro1->GetResult() << endl;
return 0;
}
使用场景
一个例子:
#include
#include
#include
using namespace std;
class Subject;
//观察者 基类 (内部实例化了被观察者的对象sub)
class Observer
{
protected:
string name;
Subject *sub;
public:
Observer(string name, Subject *sub)
{
this->name = name;
this->sub = sub;
}
virtual void update() = 0;
};
class StockObserver : public Observer
{
public:
StockObserver(string name, Subject *sub) : Observer(name, sub)
{
}
void update();
};
class NBAObserver : public Observer
{
public:
NBAObserver(string name, Subject *sub) : Observer(name, sub)
{
}
void update();
};
//被观察者 基类 (内部存放了所有的观察者对象,以便状态发生变化时,给观察者发通知)
class Subject
{
protected:
list observers;
public:
string action; //被观察者对象的状态
virtual void attach(Observer *) = 0;
virtual void detach(Observer *) = 0;
virtual void notify() = 0;
};
class Secretary : public Subject
{
void attach(Observer *observer)
{
observers.push_back(observer);
}
void detach(Observer *observer)
{
list::iterator iter = observers.begin();
while (iter != observers.end())
{
if ((*iter) == observer)
{
observers.erase(iter);
return;
}
++iter;
}
}
void notify()
{
list::iterator iter = observers.begin();
while (iter != observers.end())
{
(*iter)->update();
++iter;
}
}
};
void StockObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
}
}
void NBAObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
}
}
int main()
{
Subject *dwq = new Secretary();
Observer *xs = new NBAObserver("xiaoshuai", dwq);
Observer *zy = new NBAObserver("zouyue", dwq);
Observer *lm = new StockObserver("limin", dwq);
dwq->attach(xs);
dwq->attach(zy);
dwq->attach(lm);
dwq->action = "去吃饭了!";
dwq->notify();
cout << endl;
dwq->action = "梁所长来了!";
dwq->notify();
return 0;
}
我们一般记成SOLID
其中(里氏替换原则和迪米特法则的首字母都是L)
单一职责原则 (Single Responsibility Principle)
每个类、函数的功能定义尽量单一、精简,提高复用和可维护性,避免膨胀
开闭原则(Open Closed Principle)
对拓展开放,对修改闭合。尽量拓展,减少对原有类的直接修改,新增的功能尽量不要影响原有的功能,降低耦合风险
里氏替换原则(Liskov Subsititution Principle)
子类要实现父类的功能,可以完全替换父类。
迪米特法则(Law of Demeter),又叫"最少知道法则"
尽量对外面暴露少的接口,降低业务方使用难度
接口隔离原则(Interface Segregation Principle)
业务方尽量不要依赖它不需要的接口,这就要求基础模块能做基本的拆分,业务方按需要依赖
依赖倒置原则(dependence Inversion Principle)
依赖接口,不要依赖实现,减少耦合,增加灵活度