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 0;
}

这样调用还是会出现死循环的情况,虽然其本意是在类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)  三角问题

多个父类中重名的成员,继承到子类中后,为了避免冲突,携带了各父类的作用域信息,子类中要访问继承下来的重名成员,则会产生二义性,为了避免冲突,访问时需要提供父类的作用域信息

构造器问题

下面我们用一个实际的例子来对其进行讲解

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class X
 6 {
 7 public:
 8     X(int d)
 9     {
10         cout<<"X()"<<endl;
11     }
12 protected:
13     int _data;
14 };
15
16 class Y
17 {
18 public:
19     Y(int d)
20     {
21         cout<<"Y()"<<endl;
22     }
23 protected:
24     int _data;
25 };
26
27 class Z:public X,public Y
28 {
29 public:
30     Z()
31         :X(1),Y(2)
32     {
33
34     }
35     void dis()
36     {
37         cout<<Y_data<<endl;39     }
40 };
41
42 int main()
43 {
44     Z z;
45     z.dis();
46     return 0;
47 }

直接这样的话会报错,因为_data会产生二义性,为了解决这个问题,我们可以在数据之前加上其父类作用域

1 void dis()
2     {
3         cout<<Y::_data<<endl;
4         cout<<X::_data<<endl;
5     }

下面我们看一个有趣的情况

#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(100,200);z.dis();cout<<"================="<<endl;z.setData(1000000);cout<<z.getData()<<endl;cout<<"================="<<endl;z.dis();return 0;
}

在这里我们getData得到的数据仍然是200,并不是setData的1000000,原因如下

刚开始的时候,在类X和类Y中,都有一个_data,

当其继承在类Z中后

由于是重名的问题,setData设置的是类X中的数据,但是getData得到的是类Y中的数据,所以说会出现问题

那么我们应该怎么来解决这个问题呢

需要解决的问题:

数据冗余

访问方便

由此引发了一个三角转四角的问题

  1. 提取各父类中相同的成员,包括数据成员和函数成员,构成祖父类
  2. 让各父类,继承祖父类
  3. 虚继承是一种继承的扩展,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(100,200);z.dis();cout<<"================="<<endl;z.setData(1000000);cout<<z.getData()<<endl;cout<<"================="<<endl;z.dis();return 0;
}

这样就带来了两个好处,解决了数据冗余的问题,并且为访问带来了便利,虚继承也是一种设计的结果,被抽象上来的类叫做虚基类。也可以说成:被虚继承的类称为虚基类

虚基类:被抽象上来的类叫做虚基类

虚继承:是一种对继承的扩展

那么虚继承就有几个问题需要我们来注意了,首先是初始化的顺序问题,为了测试初始化的顺序问题,因为上述都是构造器的默认情况,但是实际情况中,可能都会带参数,甚至是虚继承的祖父类也会带参数,那么构造器顺序又将是如何的呢?我们利用如下代码进行测试

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class A
 6 {
 7 public:
 8     A(int i)
 9     {
10         _data=i;
11         cout<<"A(int i)"<<endl;
12     }
13 protected:
14     int _data;
15 };
16 class B:virtual public A
17 {
18 public:
19     B(int i)
20         :A(i)
21     {
22         _data=i;
23         cout<<"B(int i)"<<endl;
24     }
25 };
26
27 class C:virtual public A
28 {
29 public:
30     C(int i)
31         :A(i)
32     {
33         _data=i;
34         cout<<"C(int i)"<<endl;
35     }
36 };
37
38 class D:public C,B
39 {
40 public:
41     D()
42         :C(1),B(1),A(1)
43     {
44         cout<<"D(int i)"<<endl;
45     }
46     void dis()
47     {
48         cout<<_data<<endl;
49     }
50 };
51 int main()
52 {
53     D d;
54     d.dis();
55     return 0;
56 }

运行代码后我们可以得知,构造的顺序是从祖父类的构造器开始,按照顺序执行下来,最后到孙子类的构造器为止的

当然,上述只是一个测试,因为在实际过程中,祖父类是由父类抽象起来的,因此一般不会用祖父类生成对象

在实际过程中,在父类的构造器中我们常带默认参数,这样我们就可以不使得派生类的构造器如此复杂

实际例子,沙发床,除了上述之外,我们还需要增加颜色和重量,除此之外,我们还需要用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=0,int c=1){_weight=w;_color=c;}void sit(){cout<<"take a sit and have a rest"<<endl;}
};class Bed:virtual public Furniture
{
public:Bed(float w=0,int c=1){_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(1000,2);sb.sit();sb.sleep();sb.descript();return 0;
}int main1()
{Sofa sf;sf.sit();Bed bd;bd.sleep();return 0;
}

6. 多态

(1)  生活中的多态

如果有几个相似而不完全相同的对象,有时人们要求在向他们发出同一个消息时,他们的反应各不相同,分别执行不同的操作,这种情况就是多态现象

(2)  C++ 中的多态

C++ 中的多态是指,由继承而产生的相关的不同的类,其对同一消息会做出不同的响应

比如,Mspaint中的单击不同图形,执行同一拖动动作而绘制不同的图形,就是典型的多态应用

多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性,可以减轻系统的升级,维护,调试的工作量和复杂度

(3)  赋值兼容

赋值兼容是指,在需要基类对象的任何地方,都可以使用共有派生的对象来替代

只有在共有派生类中才有赋值兼容,赋值兼容是一种默认行为,不需要任何的显示的转化步骤

赋值兼容总结起来有以下三种特点

派生类的对象可以赋值给基类对象

派生类的对象可以初始化基类的引用

派生类对象的地址可以赋给指向基类的指针

下面我们将分别对其进行说明

  • 派生类的对象可以赋值给基类对象

观察下面代码

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Shape
 6 {
 7 public:
 8     Shape(int x=0,int y=0)
 9         :_x(x),_y(y){}
10     void draw()
11     {
12         cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<endl;
13     }
14 protected:
15     int _x;
16     int _y;
17 };
18 class Circle:public Shape
19 {
20 public:
21     Circle(int x=0,int y=0,int r=1)
22         :Shape(x,y),_radius(r){}
23     void draw()
24     {
25         cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<"radius:"<<_radius<<endl;
26     }
27 protected:
28     int _radius;
29 };
30 int main()
31 {
32     Shape s(1,2);
33     s.draw();
34     Circle c(4,5,6);
35     c.draw();
36     s=c; //派生类对象可以赋值给基类对象
37     s.draw();
38     return 0;
39 }

有上述例子可以看出,派生类的对象是可以复制给基类对象的

  • 派生类的对象可以初始化基类的引用
1 int main()
2 {
3     Shape s(1,2);
4     s.draw();
5     Circle c(4,5,6);
6     Shape &rs=c;
7     rs.draw();
8     return 0;
9 }

  • 派生类的对象的地址可以赋给指向基类的指针
1 int main()
2 {
3     Shape s(1,2);
4     s.draw();
5     Circle c(4,5,6);
6     Shape *ps=&c;
7     ps->draw();
8     return 0;
9 }

在这三种情况中,使用的最多的是第三种,即派生类对象的地址可以赋给指向基类的指针

就如图示一样,假设左边的类是父类,右边的类是子类,,左边的指针是派生类的对象的地址赋给指向派生类的指针,那么其可访问的范围就是整个派生类,右边的指针是派生类的对象的地址赋给指向基类的指针,那么其访问范围就只有基类的那一部分

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;
}

系统即会开始报错

  • 子类覆写父类中的虚函数,子类中同名同参同函数,才能构成覆写
  • 通过已被子类对象赋值的父类指针,调用虚函数,形成多态
 1 #include <iostream>
 2 #include <typeinfo>
 3 using namespace std;
 4
 5 class Shape
 6 {
 7 public:
 8     Shape(int x=0,int y=0)
 9         :_x(x),_y(y)
10     {
11         cout<<"shape->this"<<this<<endl;
12         cout<<typeid(this).name()<<endl;
13     }
14     virtual void draw()
15     {
16         cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<endl;
17     }
18 protected:
19     int _x;
20     int _y;
21 };
22 class Circle:public Shape
23 {
24 public:
25     Circle(int x=0,int y=0,int r=1)
26         :Shape(x,y),_radius(r)
27     {
28         cout<<"shape->this"<<this<<endl;
29         cout<<typeid(this).name()<<endl;
30     }
31     void draw()
32     {
33         cout<<"draw shape from"<<"("<<_x<<","<<_y<<")"<<"radius:"<<_radius<<endl;
34     }
35 protected:
36     int _radius;
37 };
38
39
40 class Rect:public Shape
41 {
42 public:
43     Rect(int x=0,int y=0,int w=0,int l=0)
44         :Shape(x,y),_width(w),_lenth(l){}
45     virtual void draw()
46     {
47         cout<<"draw Circle from"<<"("<<_x<<","<<_y<<")"
48            <<"width:"<<_width<<"lenth:"<<_lenth<<endl;
49     }
50 protected:
51
52     int _width;
53     int _lenth;
54 };
55
56
57 int main()
58 {
59     Circle c(3,4,5);
60     Shape *ps=&c;//父类指针指向子类的对象
61     ps->draw();
62
63     Rect r(6,7,8,9);
64     ps=&r;
65     ps->draw();
66     return 0;
67 }

可以看出,利用virtual,可以实现多态

通过父类的指针调用父类的接口指向其本来应该指向的内容

 1 int main()
 2 {
 3     Circle c(3,4,5);
 4     Shape *ps=&c;//父类指针指向子类的对象
 5     ps->draw();
 6
 7     Rect r(6,7,8,9);
 8     ps=&r;
 9     ps->draw();
10     while(1)
11     {
12         int choice;
13         cin>>choice;
14         switch(choice)
15         {
16             case 1:
17                 ps=&c;
18                 break;
19             case 2:
20                 ps=&r;
21                 break;
22         }
23         ps->draw();
24     }
25     return 0;
26 }

一个接口呈现出不同的行为,其中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文件的内容如下

 1 #ifndef ANIMAL_H
 2 #define ANIMAL_H
 3 class Animal
 4 {
 5 public:
 6     Animal();
 7     ~Animal();
 8     virtual void voice()=0;
 9 };
10 #endif // ANIMAL_H

其.cpp文件中的内容如下

 1 #include "animal.h"
 2 #include <iostream>
 3 using namespace std;
 4 Animal::Animal()
 5 {
 6     cout<<"Animal::Animal()"<<endl;
 7 }
 8
 9 Animal::~Animal()
10 {
11     cout<<"Animal::~Animal()"<<endl;
12 }

然后我们再生成Dog的.h文件

 1 #ifndef DOG_H
 2 #define DOG_H
 3 #include "animal.h"
 4 class Animal;
 5 class Dog : public Animal
 6 {
 7 public:
 8     Dog();
 9     ~Dog();
10
11     virtual void voice();
12 };
13 #endif // DOG_H

然后我们再生成Dog的.cpp文件

 1 #include "dog.h"
 2 #include "animal.h"
 3 #include <iostream>
 4 using namespace std;
 5 Dog::Dog()
 6 {
 7     cout<<"Dog::Dog()"<<endl;
 8 }
 9
10 Dog::~Dog()
11 {
12     cout<<"Dog::~Dog()"<<endl;
13 }
14
15 void Dog::voice()
16 {
17     cout<<"wang wang wang"<<endl;
18 }

然后我们生成Cat类

首先生成Cat的.h文件

 1 #ifndef CAT_H
 2 #define CAT_H
 3 #include "animal.h"
 4 class Cat : public Animal
 5 {
 6 public:
 7     Cat();
 8     ~Cat();
 9
10     virtual void voice();
11 };
12 #endif // CAT_H

然后再生成cat的.cpp文件

 1 #include "cat.h"
 2 #include "animal.h"
 3 #include <iostream>
 4 using namespace std;
 5 Cat::Cat()
 6 {
 7     cout<<"Cat::Cat()"<<endl;
 8 }
 9 Cat::~Cat()
10 {
11     cout<<"Cat::~Cat()"<<endl;
12 }
13 void Cat::voice()
14 {
15     cout<<"miao miao miao"<<endl;
16 }

最后,main函数如下

 1 #include <iostream>
 2 #include "animal.h"
 3 #include "cat.h"
 4 #include "dog.h"
 5 using namespace std;
 6
 7 int main()
 8 {
 9     Cat c;
10     Dog d;
11     Animal *pa=&c;
12     pa->voice();
13     return 0;
14 }

生成的结果为

可以看出其是析构完全了的

但是若为栈上的对象,即主函数改写为如下

 1 #include <iostream>
 2 #include "animal.h"
 3 #include "cat.h"
 4 #include "dog.h"
 5 using namespace std;
 6
 7 int main()
 8 {
 9     Animal *pa=new Dog;
10     pa->voice();
11     delete pa;
12     return 0;
13 }

得出的结果为

可以看出其是没有析构完全的,生成的Dog是没有析构的,因此对于堆上的对象,其是析构器有问题的

我们只需要解决如下

但凡类中含有虚函数(包括纯虚函数),将其虚构函数置为virtual ,这样即可以实现完整虚构

12.设计模式的原则:依赖倒置原则-核心思想:面向接口编程

传统的过程式设计倾向于使高层次的模块依赖于低层次的模块(自顶向下,逐步细化),而依据DIP的设计原则,将中间层抽象为抽象层,让高层模块和底层模块依赖于中间层

以一个例子来进行举例,用母亲给给孩子讲故事来进行举例

原本母亲给孩子讲故事是依赖于故事书上的内容,因此对于母亲给孩子讲故事我们可以写成如下代码

 1 //Mother 依赖于 Book  依赖->耦合    -->低耦合
 2 class Book
 3 {
 4 public:
 5     string getContents()
 6     {
 7         return "从前有座山,山里有座庙,庙里有个小和尚."
 8                 "听老和尚讲故事,从前有座山";
 9     }
10 };
11 class Mother
12 {
13 public:
14     void tellStory(Book &b)
15     {
16         cout<<b.getContents()<<endl;
17     }
18 };

在这里,母亲和书的关系是一种强耦合关系

即只要书的内容发生改变,Book,Mother等都需要发生改变,这样是很麻烦的

但是实际上,这种强耦合关系是我们所不希望的,为了解决这种强耦合关系,我们引入一个中间层

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 //Mother 依赖于 Book  依赖->耦合    -->低耦合
 6
 7 class IReader
 8 {
 9 public:
10     virtual string getContents()=0;
11 };
12
13 class Book:public IReader
14 {
15 public:
16     string getContents()
17     {
18         return "从前有座山,山里有座庙,庙里有个小和尚."
19                 "听老和尚讲故事,从前有座山";
20     }
21 };
22
23 class NewsPaper:public IReader
24 {
25 public:
26     string getContents()
27     {
28         return "Trump 要在黑西哥边境建一座墙";
29     }
30 };
31 class Mother
32 {
33 public:
34     void tellStory(IReader *pi)
35     {
36         cout<<pi->getContents()<<endl;
37     }
38 };
39 int main()
40 {
41     Mother m;
42     Book b;
43     NewsPaper n;
44     m.tellStory(&b);
45     m.tellStory(&n);
46     return 0;
47 }

这样的话,书改变时,Mother是不会发生改变的,只需要加一个新类就是可以的了,用户端接口不会发生改变

虚继承和虚函数总结

虚继承解决了多个父类中重名冗余的成员(包括数据成员和函数成员)

虚函数解决了多态的问题

被虚继承的类称为虚基类,含有纯虚函数的类称为抽象基类

转载于:https://www.cnblogs.com/Cucucudeblog/p/10148671.html

C++基础知识-Day8相关推荐

  1. JS基础知识day8

    知识点回顾: 动态生成html标签 空字符串 遍历数据 字符串拼接标签 var str = new String('hello') ;var arr = new Array(1,2,3) ;var f ...

  2. 嵌入式Linux的OTA更新,基础知识和实现

    嵌入式Linux的OTA更新,基础知识和实现 OTA updates for Embedded Linux, Fundamentals and implementation 更新的需要 一旦嵌入式Li ...

  3. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记

    计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...

  4. 嵌入式linux编程,嵌入式Linux学习笔记 - 嵌入式Linux基础知识和开发环境的构建_Linux编程_Linux公社-Linux系统门户网站...

    注:所有内容基于友善之臂Mini2440开发板 一.嵌入式Linux开发环境的构建 嵌入式开发一般分为三个步骤: 1.编译bootloader,烧到开发板 2.编译嵌入式Linux内核,烧到开发板 3 ...

  5. 《计算机网络应用基础》模拟试卷(六),《计算机与网络应用基础知识1》模拟试卷...

    <计算机与网络应用基础知识1>模拟试卷 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 <计算机与网络应用基础知识1& ...

  6. python向量计算库教程_NumPy库入门教程:基础知识总结

    原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...

  7. python常用变量名_python基础知识整理

    Python Python开发 Python语言 python基础知识整理 序言:本文简单介绍python基础知识的一些重要知识点,用于总结复习,每个知识点的具体用法会在后面的博客中一一补充程序: 一 ...

  8. 计算机基础知识掌握欠缺,《计算机基础知识》实验教学改革探讨.pdf

    <计算机基础知识>实验教学改革探讨.pdf Science& TechnologyVision 科 技 视 界 科技 探·索·争鸣 计<算机基础知识>实验教学改革探讨 ...

  9. python计算wav的语谱图_Python实现电脑录音(含音频基础知识讲解)

    前言 今天开始进入近期系列文章的第一篇,如何用 Python 来实现录音功能. 在开始"造轮子"之前,个人一直强调一个观点,如果有些东西已经有了,不妨直接去 github 上搜,用 ...

  10. 计算机wrod初级考试题及答案,计算机基础知识+Word基础知识+Excel基础知识试题答案解析.doc...

    文档介绍: 计算机基础知识+ Word基础知识+ Excel基础知识 第一部分 一.单项选择题 1.世界上第一台电子数字计算机取名为(    ). A.UNIVAC    B.EDSAC    C.E ...

最新文章

  1. 关于GridView手动绑定的一段代码,一切尽在不言中
  2. openCv java Mat和MatOfByte的之间的相互转换 (4)
  3. 爱奇艺蒙版AI:弹幕穿人过,爱豆心中坐
  4. 哈尔滨__伏尔加庄园
  5. 使用java解析XML文件的步骤
  6. JVM调优_堆内存溢出和非堆内存溢出
  7. ios Undefined symbols for architecture arm64
  8. doe五步法_DOE方法介绍
  9. HTML+CSS+JS做一个简易音乐播放器
  10. HBuilder配置浏览器
  11. minigui3.2 安装教程
  12. 【小程序】微信小程序自定义导航栏及其封装
  13. 2022人才市场洞察及薪酬指南
  14. innerHTML用法
  15. 人工智能、深度学习、机器学习常见面试题83~100
  16. 免费AZ-900学习资料
  17. react生命周期及hooks
  18. AJAX之四 Ajax控件工具集
  19. 系统集成项目管理工程师需要考论文吗?
  20. 骨传导耳机为什么不普及?分析骨传导耳机的利与弊

热门文章

  1. JAVASCRIPT C# 相互访问
  2. 【CyberSecurityLearning 63】CSRF攻击
  3. 【快乐水题】219. 存在重复元素 II
  4. IDEA 程序包org.springframework.web.bind.annotation不存在
  5. 一文看懂Python(六)-----类与对象篇
  6. UNIX再学习 -- 高级 I/O
  7. Hi3516A开发--编译内核、uboot
  8. /usr/include/c++/6/cstdlib:75:25: fatal error: stdlib.h: No such file or directory
  9. Java开发环境的搭建(JDK和Eclipse的安装)
  10. [以太坊源代码分析] I.区块和交易,合约和虚拟机