C++基础知识-Day8
2.类的作用域运算符
shadow
在我们之前讲的内容中,我们会发现一种情况,就是在我们在不同类中的打印函数我们都是尽量让其名字不同,那么为什么会有这种情况呢?首先我们来看一个函数
void func()
{
cout<<"B::void func()"<<endl;
func();
}
运行程序会发现这是一个死循环,因为其存在自己调用自己的情况,那么放在类中会是什么样子的呢
#include <iostream> using namespace std;
class A
{
public:
void foo()
{
cout<<"A::void foo()"<<endl;
}
};
class B:public A
{
public:
void foo()
{
cout<<"B::void foo()"<<endl;
foo();//实际上这里是有一个this指针指向foo的
}
};
int main()
{
B b;
b.foo();
return ;
}
这样调用还是会出现死循环的情况,虽然其本意是在类B中的foo调用类A中的foo,但是由于this指针指向foo并且由于类中的两个函数重名,因此会出现死循环,为了解决这个问题,引入类的作用域运算符,将类B中的foo函数写成如下形式
void foo()
{
cout<<"B::void foo()"<<endl;
A::foo();
}
shadow产生机理
(1) 在父子类中出现重名的标识符(函数成员和数据成员),就会构成shadow,如果想访问被shadow的成员,加上父类的命名空间
(2) shadow在父子类中的标识符只有一个,就是重名,不论返回值,参数不同什么
3. 继承的方式详解
继承的方式有三种:public,protected和private,但是我们一般都用public
所有的继承必须是public的,如果想私有继承的话,应该采用将基类实例作为成员的方式作为替代
一般情况下,在一个类中,public常用于接口,protected常用于数据,private常用于隐私
那么为什么public是用的最多的呢
如果多级派生中,均采用public,直到最后一级,派生类中均可访问基类的public,protected,很好的做到了接口的传承,保护数据以及隐私的保护
protected:封杀了对外的接口,保护数据成员,隐私保护
public:传承接口,间接地传承了数据(protected)
protected:传承数据,间接封杀了对外接口(public)
private:统杀了数据和接口
4. 类的作用域运算符
shadow产生机理
(1) 在父子类中出现重名的标识符(函数成员和数据成员),就会构成shadow,如果想访问被shadow的成员,加上父类的命名空间
(2) shadow在父子类中的标识符只有一个,就是重名,不论返回值,参数不同什么
5. 多重继承
从继承类别来说,继承可以分为单继承和多继承
多继承的意义:
俗话讲,鱼和熊掌不可兼得,而在计算机中可以实现,生成一种新的对象,叫熊掌鱼,多继承自鱼和熊掌即可
继承语法:
派生类名:public 基类名1,public 基类名2,…,protected 基类名n
构造器格式
派生类名:派生类名(总参列表)
:基类名1(参数表1),基类名2(参数名2),…基类名n(参数名n),
内嵌子对象1(参数表1),内嵌子对象2(参数表2)…内嵌子对象n(参数表n)
{
派生类新增成员的初始化语句
}
多继承可能存在的问题
(1) 三角问题
多个父类中重名的成员,继承到子类中后,为了避免冲突,携带了各父类的作用域信息,子类中要访问继承下来的重名成员,则会产生二义性,为了避免冲突,访问时需要提供父类的作用域信息
构造器问题
下面我们用一个实际的例子来对其进行讲解
#include <iostream> using namespace std; class X
{
public:
X(int d)
{
cout<<"X()"<<endl;
}
protected:
int _data;
}; class Y
{
public:
Y(int d)
{
cout<<"Y()"<<endl;
}
protected:
int _data;
}; class Z:public X,public Y
{
public:
Z()
:X(),Y()
{ }
void dis()
{
cout<<Y_data<<endl; }
}; int main()
{
Z z;
z.dis();
return ;
}
直接这样的话会报错,因为_data会产生二义性,为了解决这个问题,我们可以在数据之前加上其父类作用域
void dis()
{
cout<<Y::_data<<endl;
cout<<X::_data<<endl;
}
下面我们看一个有趣的情况
#include <iostream> using namespace std; class X
{
public:
X(int d)
{
cout<<"X()"<<endl;
_data=d;
}
void setData(int d)
{
_data=d;
}
protected:
int _data;
}; class Y
{
public:
Y(int d)
{
cout<<"Y()"<<endl;
_data=d;
}
int getData()
{
return _data;
}
protected:
int _data;
}; class Z:public X,public Y
{
public:
Z(int i,int j)
:X(i),Y(j)
{ }
void dis()
{
cout<<X::_data<<endl;
cout<<Y::_data<<endl;
}
}; int main()
{
Z z(,);
z.dis();
cout<<"================="<<endl;
z.setData();
cout<<z.getData()<<endl;
cout<<"================="<<endl;
z.dis();
return ;
}
在这里我们getData得到的数据仍然是200,并不是setData的1000000,原因如下
刚开始的时候,在类X和类Y中,都有一个_data,
当其继承在类Z中后
由于是重名的问题,setData设置的是类X中的数据,但是getData得到的是类Y中的数据,所以说会出现问题
那么我们应该怎么来解决这个问题呢
需要解决的问题:
数据冗余
访问方便
由此引发了一个三角转四角的问题
- 提取各父类中相同的成员,包括数据成员和函数成员,构成祖父类
- 让各父类,继承祖父类
- 虚继承是一种继承的扩展,virtual
首先解决初始化问题,
祖父类的好处是,祖父类是默认的构造器,因此在父类中,并不需要显示地调用,按道理说,Z中有类X,Y,只需要管X,Y的初始化就可以了
#include <iostream> using namespace std; //祖父类
class A
{
protected:
int _data;
};
//父类继承祖父类
class X:virtual public A
{
public:
X(int d)
{
cout<<"X()"<<endl;
_data=d;
}
void setData(int d)
{
_data=d;
} };
//各父类继承祖父类
class Y:virtual public A
//虚继承
{
public:
Y(int d)
{
cout<<"Y()"<<endl;
_data=d;
}
int getData()
{
return _data;
}
}; class Z:public X,public Y
{
public:
Z(int i,int j)
:X(i),Y(j)
{ }
void dis()
{
cout<<_data<<endl;
}
}; int main()
{
Z z(,);
z.dis();
cout<<"================="<<endl;
z.setData();
cout<<z.getData()<<endl;
cout<<"================="<<endl;
z.dis();
return ;
}
这样就带来了两个好处,解决了数据冗余的问题,并且为访问带来了便利,虚继承也是一种设计的结果,被抽象上来的类叫做虚基类。也可以说成:被虚继承的类称为虚基类
虚基类:被抽象上来的类叫做虚基类
虚继承:是一种对继承的扩展
那么虚继承就有几个问题需要我们来注意了,首先是初始化的顺序问题,为了测试初始化的顺序问题,因为上述都是构造器的默认情况,但是实际情况中,可能都会带参数,甚至是虚继承的祖父类也会带参数,那么构造器顺序又将是如何的呢?我们利用如下代码进行测试
#include <iostream> using namespace std; class A
{
public:
A(int i)
{
_data=i;
cout<<"A(int i)"<<endl;
}
protected:
int _data;
};
class B:virtual public A
{
public:
B(int i)
:A(i)
{
_data=i;
cout<<"B(int i)"<<endl;
}
}; class C:virtual public A
{
public:
C(int i)
:A(i)
{
_data=i;
cout<<"C(int i)"<<endl;
}
}; class D:public C,B
{
public:
D()
:C(),B(),A()
{
cout<<"D(int i)"<<endl;
}
void dis()
{
cout<<_data<<endl;
}
};
int main()
{
D d;
d.dis();
return ;
}
运行代码后我们可以得知,构造的顺序是从祖父类的构造器开始,按照顺序执行下来,最后到孙子类的构造器为止的
当然,上述只是一个测试,因为在实际过程中,祖父类是由父类抽象起来的,因此一般不会用祖父类生成对象
在实际过程中,在父类的构造器中我们常带默认参数,这样我们就可以不使得派生类的构造器如此复杂
实际例子,沙发床,除了上述之外,我们还需要增加颜色和重量,除此之外,我们还需要用descript函数来对其进行描述
#include <iostream> using namespace std; class Furniture
{
public:
void descript()
{
cout<<"_weight:"<<_weight<<endl;
cout<<"_color :"<<_color<<endl;
}
protected:
float _weight;
int _color;
};
class Sofa:virtual public Furniture
{
public:
Sofa(float w=,int c=)
{
_weight=w;
_color=c;
}
void sit()
{
cout<<"take a sit and have a rest"<<endl;
}
}; class Bed:virtual public Furniture
{
public:
Bed(float w=,int c=)
{
_weight=w;
_color=c;
}
void sleep()
{
cout<<"have a sleep ......."<<endl;
} }; class SofaBed:public Sofa,public Bed
{
public:
SofaBed(float w,int c)
{
_weight=w;
_color=c;
}
}; int main()
{
SofaBed sb(,);
sb.sit();
sb.sleep();
sb.descript();
return ;
} int main1()
{
Sofa sf;
sf.sit();
Bed bd;
bd.sleep();
return ;
}
6. 多态
(1) 生活中的多态
如果有几个相似而不完全相同的对象,有时人们要求在向他们发出同一个消息时,他们的反应各不相同,分别执行不同的操作,这种情况就是多态现象
(2) C++ 中的多态
C++ 中的多态是指,由继承而产生的相关的不同的类,其对同一消息会做出不同的响应
比如,Mspaint中的单击不同图形,执行同一拖动动作而绘制不同的图形,就是典型的多态应用
多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性,可以减轻系统的升级,维护,调试的工作量和复杂度
(3) 赋值兼容
赋值兼容是指,在需要基类对象的任何地方,都可以使用共有派生的对象来替代
只有在共有派生类中才有赋值兼容,赋值兼容是一种默认行为,不需要任何的显示的转化步骤
赋值兼容总结起来有以下三种特点
派生类的对象可以赋值给基类对象 |
派生类的对象可以初始化基类的引用 |
派生类对象的地址可以赋给指向基类的指针 |
下面我们将分别对其进行说明
- 派生类的对象可以赋值给基类对象
观察下面代码
#include <iostream> using namespace std; class Shape
{
public:
Shape(int x=,int y=)
:_x(x),_y(y){}
void draw()
{
cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<endl;
}
protected:
int _x;
int _y;
};
class Circle:public Shape
{
public:
Circle(int x=,int y=,int r=)
:Shape(x,y),_radius(r){}
void draw()
{
cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<"radius:"<<_radius<<endl;
}
protected:
int _radius;
};
int main()
{
Shape s(,);
s.draw();
Circle c(,,);
c.draw();
s=c; //派生类对象可以赋值给基类对象
s.draw();
return ;
}
有上述例子可以看出,派生类的对象是可以复制给基类对象的
- 派生类的对象可以初始化基类的引用
int main()
{
Shape s(,);
s.draw();
Circle c(,,);
Shape &rs=c;
rs.draw();
return ;
}
- 派生类的对象的地址可以赋给指向基类的指针
int main()
{
Shape s(,);
s.draw();
Circle c(,,);
Shape *ps=&c;
ps->draw();
return ;
}
在这三种情况中,使用的最多的是第三种,即派生类对象的地址可以赋给指向基类的指针
就如图示一样,假设左边的类是父类,右边的类是子类,,左边的指针是派生类的对象的地址赋给指向派生类的指针,那么其可访问的范围就是整个派生类,右边的指针是派生类的对象的地址赋给指向基类的指针,那么其访问范围就只有基类的那一部分
7. 多态
多态分为静多态和动多态
静多态,就是我们说的函数重载,表面上,是由重载规则来限定的,内部实现却是Namemangling,此种行为,发生在编译期,故称为静多态
(动)多态,不是在编译阶段决定,而是在运行阶段决定,故称动多态,动多态的形成条件如下
多态实现的条件
父类中有虚函数(加virtual,是一个声明型关键字,即只能在声明中有,在实现中没有),即公用接口 |
子类override(覆写)父类中的虚函数 |
通过已被子类对象赋值的父类指针,调用共有接口 |
下面分别对这些条件进行讲解
- 父类中有虚函数(加virtual,是一个声明型关键字,即只能在声明中有,在实现中没有),即公用接口
virtual函数是一个声明型关键字,只能在声明中有,在实现中没有
class A
{
public:
A(){};
virtual void draw();
private:
int _x;
}
void A::draw()
{
cout<<_x<<endl;
}
假设在实现的过程中也加入virtual关键字,即
virtual void A::draw()
{
cout<<_x<<endl;
}
系统即会开始报错
- 子类覆写父类中的虚函数,子类中同名同参同函数,才能构成覆写
- 通过已被子类对象赋值的父类指针,调用虚函数,形成多态
#include <iostream>
#include <typeinfo>
using namespace std; class Shape
{
public:
Shape(int x=,int y=)
:_x(x),_y(y)
{
cout<<"shape->this"<<this<<endl;
cout<<typeid(this).name()<<endl;
}
virtual void draw()
{
cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<endl;
}
protected:
int _x;
int _y;
};
class Circle:public Shape
{
public:
Circle(int x=,int y=,int r=)
:Shape(x,y),_radius(r)
{
cout<<"shape->this"<<this<<endl;
cout<<typeid(this).name()<<endl;
}
void draw()
{
cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<"radius:"<<_radius<<endl;
}
protected:
int _radius;
}; class Rect:public Shape
{
public:
Rect(int x=,int y=,int w=,int l=)
:Shape(x,y),_width(w),_lenth(l){}
virtual void draw()
{
cout<<"draw Circle from"<<"("<<_x<<","<<_y<<")"
<<"width:"<<_width<<"lenth:"<<_lenth<<endl;
}
protected: int _width;
int _lenth;
}; int main()
{
Circle c(,,);
Shape *ps=&c;//父类指针指向子类的对象
ps->draw(); Rect r(,,,);
ps=&r;
ps->draw();
return ;
}
可以看出,利用virtual,可以实现多态
通过父类的指针调用父类的接口指向其本来应该指向的内容
int main()
{
Circle c(,,);
Shape *ps=&c;//父类指针指向子类的对象
ps->draw(); Rect r(,,,);
ps=&r;
ps->draw();
while()
{
int choice;
cin>>choice;
switch(choice)
{
case :
ps=&c;
break;
case :
ps=&r;
break;
}
ps->draw();
}
return ;
}
一个接口呈现出不同的行为,其中virtual是一个声明型关键字,用来声明一个虚函数,子类覆写了的函数,也是virtual
虚函数在子函数中的访问属性并不影响多态,要看子类
虚函数和多态总结
(1)virtual是声明函数的关键字,他是一个声明型关键字
(2)override构成的条件,发生在父子类的继承关系中,同名,同参,同返回
(3)虚函数在派生类中仍然为虚函数,若发生覆写,最好显示的标注virtual
(4)子类中覆写的函数,可以为任意的访问类型,依子类需求决定
8. pure virtual function
纯虚函数,指的是virtual修饰的函数,没有实现体,被初始化为0,被高度抽象化的具有纯接口类才配有纯虚函数,含有纯虚函数的类称为抽象基类
抽象基类不能实例化(不能生成对象),纯粹用来提供接口用的
子类中若无覆写,则依然为纯虚,依然不能实例化
9. 总结
(1)纯虚函数只有声明,没有实现,被“初始化”为0
(2)含有纯虚函数的类,称为Abstract Base Class(抽象基类),不能实例化,即不能创造对象,存在的意义就是被继承,而在派生类中没有该函数的意义
(3)如果一个中声明了纯虚函数,而在派生类中没有该函数的定义,则该虚函数在派生类中仍然为虚函数,派生类仍然为纯虚基类
10. 析构函数
含有虚函数的类,析构函数也应该声明为虚函数
这是为了保证对象析构的完整性,具体的情况就是父类的指针指向子类的堆对象,此时通过父类指针去析构子类堆对象时就会虚构不完整,为了保证析构的完整性,含有虚函数的类将其析构函数也声明为虚函数(virtual)
对比栈对象和对对象在多态中销毁的不同
首先我们来看位于栈上的对象
在这里,我们生成了几个类,一个是抽象基类,一个是Dog类,一个是Cat类,我们分别在class中去构造这几个类
首先生成Animal类
其.h文件的内容如下
#ifndef ANIMAL_H
#define ANIMAL_H
class Animal
{
public:
Animal();
~Animal();
virtual void voice()=;
};
#endif // ANIMAL_H
其.cpp文件中的内容如下
#include "animal.h"
#include <iostream>
using namespace std;
Animal::Animal()
{
cout<<"Animal::Animal()"<<endl;
} Animal::~Animal()
{
cout<<"Animal::~Animal()"<<endl;
}
然后我们再生成Dog的.h文件
#ifndef DOG_H
#define DOG_H
#include "animal.h"
class Animal;
class Dog : public Animal
{
public:
Dog();
~Dog(); virtual void voice();
};
#endif // DOG_H
然后我们再生成Dog的.cpp文件
#include "dog.h"
#include "animal.h"
#include <iostream>
using namespace std;
Dog::Dog()
{
cout<<"Dog::Dog()"<<endl;
} Dog::~Dog()
{
cout<<"Dog::~Dog()"<<endl;
} void Dog::voice()
{
cout<<"wang wang wang"<<endl;
}
然后我们生成Cat类
首先生成Cat的.h文件
#ifndef CAT_H
#define CAT_H
#include "animal.h"
class Cat : public Animal
{
public:
Cat();
~Cat(); virtual void voice();
};
#endif // CAT_H
然后再生成cat的.cpp文件
#include "cat.h"
#include "animal.h"
#include <iostream>
using namespace std;
Cat::Cat()
{
cout<<"Cat::Cat()"<<endl;
}
Cat::~Cat()
{
cout<<"Cat::~Cat()"<<endl;
}
void Cat::voice()
{
cout<<"miao miao miao"<<endl;
}
最后,main函数如下
#include <iostream>
#include "animal.h"
#include "cat.h"
#include "dog.h"
using namespace std; int main()
{
Cat c;
Dog d;
Animal *pa=&c;
pa->voice();
return ;
}
生成的结果为
可以看出其是析构完全了的
但是若为栈上的对象,即主函数改写为如下
#include <iostream>
#include "animal.h"
#include "cat.h"
#include "dog.h"
using namespace std; int main()
{
Animal *pa=new Dog;
pa->voice();
delete pa;
return ;
}
得出的结果为
可以看出其是没有析构完全的,生成的Dog是没有析构的,因此对于堆上的对象,其是析构器有问题的
我们只需要解决如下
但凡类中含有虚函数(包括纯虚函数),将其虚构函数置为virtual ,这样即可以实现完整虚构
12.设计模式的原则:依赖倒置原则-核心思想:面向接口编程
传统的过程式设计倾向于使高层次的模块依赖于低层次的模块(自顶向下,逐步细化),而依据DIP的设计原则,将中间层抽象为抽象层,让高层模块和底层模块依赖于中间层
以一个例子来进行举例,用母亲给给孩子讲故事来进行举例
原本母亲给孩子讲故事是依赖于故事书上的内容,因此对于母亲给孩子讲故事我们可以写成如下代码
//Mother 依赖于 Book 依赖->耦合 -->低耦合
class Book
{
public:
string getContents()
{
return "从前有座山,山里有座庙,庙里有个小和尚."
"听老和尚讲故事,从前有座山";
}
};
class Mother
{
public:
void tellStory(Book &b)
{
cout<<b.getContents()<<endl;
}
};
在这里,母亲和书的关系是一种强耦合关系
即只要书的内容发生改变,Book,Mother等都需要发生改变,这样是很麻烦的
但是实际上,这种强耦合关系是我们所不希望的,为了解决这种强耦合关系,我们引入一个中间层
#include <iostream> using namespace std; //Mother 依赖于 Book 依赖->耦合 -->低耦合 class IReader
{
public:
virtual string getContents()=;
}; class Book:public IReader
{
public:
string getContents()
{
return "从前有座山,山里有座庙,庙里有个小和尚."
"听老和尚讲故事,从前有座山";
}
}; class NewsPaper:public IReader
{
public:
string getContents()
{
return "Trump 要在黑西哥边境建一座墙";
}
};
class Mother
{
public:
void tellStory(IReader *pi)
{
cout<<pi->getContents()<<endl;
}
};
int main()
{
Mother m;
Book b;
NewsPaper n;
m.tellStory(&b);
m.tellStory(&n);
return ;
}
这样的话,书改变时,Mother是不会发生改变的,只需要加一个新类就是可以的了,用户端接口不会发生改变
虚继承和虚函数总结
虚继承解决了多个父类中重名冗余的成员(包括数据成员和函数成员)
虚函数解决了多态的问题
被虚继承的类称为虚基类,含有纯虚函数的类称为抽象基类
C++基础知识-Day8的更多相关文章
- python基础知识-day8(动态参数)
1.动态参数 函数的形式参数个数不确定.函数的形式数据类型不确定,使用动态参数,*代表元组,**代表字典. 2.代码案例演示 1 def func(*args,**kwargs): 2 print(a ...
- python基础知识-day8(函数实战)
1 def out(): 2 username=input("请输入用户名:\n") 3 password=input("请输入密码:\n") 4 return ...
- python基础知识-day8(模块与包、random、os)
1.模块与包 package:相同的模块代码存储在一个目录下(即包里边会包含多个模块). 包不能存储在文件夹的目录下,模块名称不能使用关键字.(不包含工程文件夹) 2.模块与包的实例 1)在工程文 ...
- .NET面试题系列[1] - .NET框架基础知识(1)
很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...
- RabbitMQ基础知识
RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- selenium自动化基础知识
什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...
- [SQL] SQL 基础知识梳理(一)- 数据库与 SQL
SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...
- [SQL] SQL 基础知识梳理(二) - 查询基础
SQL 基础知识梳理(二) - 查询基础 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5904824.html 序 这是<SQL 基础知识梳理( ...
- [SQL] SQL 基础知识梳理(三) - 聚合和排序
SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...
随机推荐
- docker学习笔记二
知识点: 1)手动构建镜像 2)Dockerfile快速构建镜像 阿里云yum源https://opsx.alibaba.com/mirror 镜像制作nginx镜像实例 创建并运行centos容器 ...
- Yii2控制台命令
Yii2控制台表格输出: 例如: $in_sheet_number_queue = []; $wms_material_in_sheet_list = \core\models\WmsMaterial ...
- ASP.NET MVC和Web API中的Angular2 - 第1部分
下载源码 - 903.5 KB 内容 第1部分:Visual Studio 2017中的Angular2设置,基本CRUD应用程序,第三方模态弹出控件 第2部分:使用Angular2管道进行过滤/搜索 ...
- 51nod1016
1016 水仙花数 V2 1 秒 131,072 KB 160 分 6 级题 水仙花数是指一个 n 位数 ( n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身.(例如:1^3 + 5^3 ...
- Auth模块使用方法大全
auth认证 导包 from django.contrib import auth 默认数据库中使用auth_user表 创建超级用户 python manage.py createsuperuser ...
- robotframework测试用例加入注释
*** Variables ***${HOST} 192.168.132.135${USER} username*** Test Cases ***Simple [Documentation] Sim ...
- 【XSY1529】小Q与进位制 分治 FFT
题目大意 小Q发明了一种进位制,每一位的变化范围是\(0\)~\(b_i-1\),给你一个这种进位制下的整数\(a\),问你有多少非负整数小于\(a\).结果以十进制表示. \(n\leq 1 ...
- bzoj 2131 : 免费的馅饼 (树状数组优化dp)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2131 思路: 题目给出了每个馅饼的下落时间t,和位置p,以及价值v,我们可以得到如下状态 ...
- bzoj 4542: [Hnoi2016]大数 (莫队)
Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个 ...
- Concurrent usage detected
同一个公司里,使用studio 同时进行开发,而且账号还是同一个,会出现这种问题 也有说封掉8732端口就可以解决这个问题的,但是我尝试的是不行的 一直以来用的一个笨的但是有效的办法是:启动studi ...