专栏首页架构说60秒问答:多态和函数重载的关系?

60秒问答:多态和函数重载的关系?

目录:阅读该文章将获得如下收益

  • 什么是多态,与重载,重写,隐藏什么关系?
  • 名词隐藏机制和重载 new 函数 例子(liunx api返回值设计 1返回错误 2 抛异常3 抛信号)
  • 隐藏可以避免吗,在c++11中呢?
  • 函数重载与stl萃取机制结合 实现编译时多态
  • 汇编查看虚函数指针与构造 和析构函数关系。

60秒问答

一、 问:重载,重写 ,隐藏区别?

答:

  1. 重载 相同作用域内,函数名字相同,参数不同。
  2. 重写 不用作用域 , 函数名字相同,参数相同。
  3. 隐藏:不用作用域, 通过派生类访问:派生类同名函数,隐藏基类函数 或者通过基类指针访问,基类函数隐藏派生类。

二、 问题:如何解隐藏问题?

答:隐藏分为2个情况,同名函数查找过程 派生类 基类 全局

情况1 如果是通过派生类访问一个函数,派生类局部作用域隐藏上层 base同名函数。

  1. 为了让隐藏起来的名字重见天日,使用using声明
  2. 通过base类指针或者引用访问 (这个和虚函数无关)

情况2 如果是通过通过base类指针或者引用访问 隐藏派生类同名函数。

通过虚函数解决

三、 问 什么是多态?怎么实现的

答:

多态:同一个函数,不同的行为。具体选择那个行为 2个情况。

编译时的多态:函数重载和运算符重载(根据参数不同选择具体函数 )

运行时的多态:通过类继承和虚函数实现的(根据虚表指针 指向 派生类的函数,还是基类的函数)

四、 类型转换有几种情况,有什么区别?

答:

  1. 自动类型转换,缺点有可能丢失精度(派生类转换base类,3.14--3)
  2. 静态转换 动态转换 强制转换 和解释转换 3、 区别:静态转换 任何类型

解释

到底什么是多态?这个概念很模糊,不清楚,

就是具体执行那个函数吗?

  • case1. if a if b, if c 是多态吗?表现不一样。

整理这个文章之后,依然不清楚,有了解的可以告诉我

我知道的

面向对象的三大特征:

1.封装:保证对象自身数据的完整性、安全性

2.继承:建立类之间的关系,实现代码复用、方便系统的扩展

3.多态:相同的方法调用可实现不同的实现方式。【定义】

多态是指两个或多个属于不同类的对象,对于同一个消息(方法调用)作出不同响应的方式。

、、、、、、、、、

实现多态的方式【为什么3个情况,不是一个情况】

  1. 函数重载;
  2. 运算符重载;
  3. 虚函数

、、、、、、、、、

  • 多态性指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。[定义]

C++支持两种多态性:编译时多态性,运行时多态性。

1.编译时的多态:函数重载和运算符重载,在编译时就决定调用哪个函数,先期联编 early binding

2.运行时的多态:通过类继承和虚函数实现的

C++运行时多态性是通过虚函数来实现的,

虚函数允许子类重新定义成员函数,

而子类重新定义父类的做法称为覆盖(Override),或者称为重写。

  • 多态与非多态的实质区别就是函数地址是早绑定

1.2 运算符 operator= 重载例子 【STL源码剖析简体】

  • STL—Iterator的分类和copy的重载及其使用
  • https://www.cplusplus.com/reference/iterator/insert_iterator/
template <class _Container>
class insert_iterator {
protected:
  _Container* container;
  typename _Container::iterator iter;
public:

  operator=(const typename _Container::value_type& __value) { 
    iter = container->insert(iter, __value);
    ++iter;
    return *this;
  }
  
};

// insert_iterator example
#include <iostream>     // std::cout
#include <iterator>     // std::insert_iterator
#include <list>         // std::list
#include <algorithm>    // std::copy

int main () {
  std::list<int> foo, bar;
  for (int i=1; i<=5; i++)
  { foo.push_back(i); bar.push_back(i*10); }

  std::list<int>::iterator it = foo.begin();
  advance(it,3);

  std::insert_iterator< std::list<int> > insert_it (foo,it);

  std::copy (bar.begin(),bar.end(),insert_it);

  std::cout << "foo:";
  for ( std::list<int>::iterator it = foo.begin(); it!= foo.end(); ++it )
   std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

1 2 3 10 20 30 40 50 4 5

我不知道的:什么是可扩展的多态

多态性机制不仅增加了面向对象软件系统的灵活性,进一步减少了冗余信息, 而且显著提高了软件的可重用性和可扩充性。

从实现的角度来讲,c++多态性可以划分为两类

  1. 编译时的多态:函数重载和运算符重载,在编译时就决定调用哪个函数
    • 重载 编译时的多态
    • 重载指允许【在相同作用域中】存在多个同名的函数,这些函数的参数表不同
  2. 运行时的多态:通过类继承和虚函数实现的,在运行时就就决定调用哪个函数
    • 重写(override)就是一种运行时多态
    • 覆盖是存在类中,【子类重写】从基类继承过来的函数,函数名、返回值、参数列表都必须和基类相同

重载,重写都出现了,隐藏呢:

  • 是指派生类的函数屏蔽了与其同名的基类函数, 注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。

作用域与名字隐藏机制

数据隐藏

int n = 1;//全局作用域
int main()
{
 int n = 2;//局部作用域
 {
  int n = 3;//块作用域
 }
}

转载自《C++ exceptional style》第22条

隐藏经常发生在继承关系中,派生类重新定义了基类的非virtual函数【虚函数也隐藏】,当发生隐藏时,编译器名字隐藏机制如下:

1. 编译器会从当前域开始查找(比如派生类对象调用,会在派生类的定义内查找),查找需要的名字;

2. 如果在当前域没有找到,编译器会在外围作用域继续查找,先是基类的定义内,然后是全局名字空间;

3. 一旦在某个作用域内包含需要的名字就会停下来,并就该作用域内的名字进行决议
,这意味着往外层的作用域就不予考虑了,从而将外层作用域的同名函数隐藏;[不在去寻找更合适的]

4.编译器在当前的名字空间中找到与所求名字同名的实体之间进行决议(函数重载),如果选不出最优,就产生二义性错误;[寻找不到,然后报错]

5. 选出最优的函数,查看函数是否可以访问/调用




IF 子类的函数与父类的名称相同,但是参数不同

父类函数被隐藏

ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数没有virtual

父类函数被隐藏

ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数有virtual

父类函数被覆盖

C++名字隐藏机制例子1

全局:重载3个operator new

new 是可以被重载的

  • void* operator new (std::size_t size)
  • void* operator new (std::size_t size, const std::nothrow_t& nothrow_value)
  • void* operator new (std::size_t size, void* ptr)
https://www.cplusplus.com/reference/new/operator%20new/

throwing (1) void* operator new (std::size_t size);

nothrow (2) void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;

placement (3) 
void* operator new (std::size_t size, void* ptr) noexcept;


// operator new example
#include <iostream>     // std::cout
#include <new>          // ::operator new
struct MyClass {
  int data[100];
  MyClass() {std::cout << "constructed [" << this << "]\n";}
};

int main () {
  std::cout << "1: ";
  MyClass * p1 = new MyClass;
      // allocates memory by calling: operator new (sizeof(MyClass)) 
      //1 计算大小 
      //2 调用 operator new
      // and then constructs an object at the newly allocated space 
      //3 执行构造函数

  std::cout << "2: ";
  
  MyClass * p2 = new (std::nothrow) MyClass; 
      // allocates memory by calling: operator new (sizeof(MyClass),std::nothrow)
      // and then constructs an object at the newly allocated space
      // 返回值为0 ,不抛异常。

  std::cout << "3: ";
  new (p2) MyClass;
      // does not allocate memory -- calls: operator new (sizeof(MyClass),p2)
      // but constructs an object at p2

  // Notice though that calling this function directly does not construct an object:
  std::cout << "4: ";
  MyClass * p3 = (MyClass*) ::operator new (sizeof(MyClass));
      // allocates memory by calling: operator new (sizeof(MyClass))
      // but does not call MyClass's constructor
  return 0;
}

局部只重载placement new,遗忘另外2个情况(不抛出异常和抛异常)

继承体系中的名字是如何被隐藏的
  • 首先编译器在Derived类内查找new函数,没有找到名字;
  • 编译器往外一层查找new,在基类Base定义内查找,找到了new函数,就不继续考虑全局空间的定义了
  • 基类只定义了一个new运算符,把简单new,定位new和nothrow new都隐藏了,导致无匹配的版本可使用
//例子 名字隐藏了new
 
 class Base
 {
 public:
     static void* operator new(std::size_t, const FastMemory&);
 };
 
 class Derived: public Base
 {
     Derived *p1 = new Derived;              //错误,无可用的匹配,因为简单new被隐藏
     Derived *p2 = new(std::nothrow) Derived;     //错误,无可用的匹配,因为nothrow new被隐藏
 
     void *p3 = /* 足够放下一个Derived对象 */        
     new(p3) Derived;                                //错误,无可用的匹配,因为定位new被隐藏
     
     FastMemroy f;
     Derived *p4 = new(f) Derived;                   //调用Base::operator new()
}

普通函数的隐藏

(1)函数Derived::f(float)覆盖了Base::f(float)。父类函数被覆盖

(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。不相同的参数

(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。相同的参数

  • 特点:IF 子类的函数与父类的名称相同,但是参数不同

父类函数被隐藏

ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数没有virtual

父类函数被隐藏

ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数有virtual

父类函数被覆盖

#include <iostream>

using namespace std;

class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    void g(float x){ cout << "Base::g(float) " << x << endl; }
    void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    void g(int x){ cout << "Derived::g(int) " << x << endl; }
    void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

int main(void)
{
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    // Good : behavior depends solely on type of the object
    pb->f(3.14f); //Derived::f(float) 3.14  
   // 函数Derived::f(float)覆盖了Base::f(float) 多态
    pd->f(3.14f); //Derived::f(float) 3.14  非多态

    // Bad : behavior depends on type of the pointer
    pb->g(3.14f); //Base::g(float) 3.14
    pd->g(3.14f); //Derived::g(int) 3  
    //函数Derived::g(int)隐藏了Base::g(float),不相同的参数

    // Bad : behavior depends on type of the pointer
    pb->h(3.14f); //Base::h(float) 3.14
    pd->h(3.14f); //Derived::h(float) 3.14
    // 函数Derived::h(float)隐藏了Base::h(float),相同的参数
   


    return 0;
}


[root@VM-0-10-centos work]# ./a.out
Derived::f(float) 3.14
Derived::f(float) 3.14

Base::g(float) 3.14
Derived::g(int) 3

Base::h(float) 3.14
Derived::h(float) 3.14

错误理解:

  • 直接回答隐藏无法避免是错误的,没有区分 参数相同,参数不同。

三、如何将隐藏行为覆盖掉

情况1 如果是通过派生类访问一个函数,派生类局部作用域隐藏上层 base类函数

  1. 为了让隐藏起来的名字重见天日,使用using声明
  2. 通过base类指针或者引用访问 (这个和虚函数无关)

情况2 如果是通过通过base类指针或者引用访问 隐藏派生类同名函数。

通过虚函数解决

   // Good : behavior depends solely on type of the object
    pb->f(3.14f); //Derived::f(float) 3.14  
   // 函数Derived::f(float)覆盖了Base::f(float) 多态
    pd->f(3.14f); //Derived::f(float) 3.14  非多态

3.1 C++核心准则C.138:使用using为派生类生成重载函数集

C.138: Create an overload set for a derived class and its bases with using

原文链接:

  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c138-create-an-overload-set-for-a-derived-class-and-its-bases-with-using
  • http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c138-create-an-overload-set-for-a-derived-class-and-its-bases-with-using
  • https://www.cnblogs.com/harlanc/p/6556371.html
C.138: Create an overload set for a derived class and its bases with using

Reason


Without a using declaration, member functions in the derived class hide the entire inherited overload sets.

如果没有using声明,派生类中的成员函数将隐藏整个继承的重载集。


Example, bad
#include <iostream>
class B {
public:
    virtual int f(int i) { std::cout << "f(int): "; return i; }
    virtual double f(double d) { std::cout << "f(double): "; return d; }
    virtual ~B() = default;
};
class D: public B {
public:
    int f(int i) override { std::cout << "f(int): "; return i + 1; }
};
int main()
{
    D d;
    std::cout << d.f(2) << '\n';   // prints "f(int): 3"
    std::cout << d.f(2.3) << '\n'; // prints "f(int): 3"
}

//在此证明 虚函数无法解决参数不相同的隐藏问题


Example, good
class D: public B {
public:
    int f(int i) override { std::cout << "f(int): "; return i + 1; }
    using B::f; // exposes f(double)
};
Note This issue affects both virtual and non-virtual member functions
For variadic bases, C++17 introduced a variadic form of the using-declaration,

template<class... Ts>
struct Overloader : Ts... {
    using Ts::operator()...; // exposes operator() from every base
};

Enforcement 

Diagnose 
name hiding
名称隐藏


C.140: Do not provide different default arguments for a virtual function and an overrider
Reason That can cause confusion: An overrider does not inherit default arguments.Example, bad
class Base {
public:
    virtual int multiply(int value, int factor = 2) = 0;
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    int multiply(int value, int factor = 10) override;
};

Derived d;
Base& b = d;

b.multiply(10);  // these two calls will call the same function but
d.multiply(10);  // with different arguments and so different results

  • 警告:

青铜回答:用override解决隐藏?

点评:

  • 这个想法是错误的,一看就没有经过验证,这个认知要纠正
  • C++11 中的 override 关键字,可以显式的在派生类中声明,哪些成员函数需要被重写,如果没被重写,则编译器会报错。[表示这个函数一定是base出现过的。]

3.2 普通函数

--example 1--
#include<iostream>
using namespace std;
namespace Lib
{
    void print(int x)
    {
        cout<<"int"<<x<<endl;
    }
}
void print(double y){
        cout<<"double"<<y<<endl;
    }
int main()
{
    using Lib::print;//example 1 : main作用域中嵌套了Lib命名空间
    print(1.3);
    print(3);
    getchar();
    return 1;
}
//输出:
int 1
int 3

1.3 函数参数传递 与类型转换

  • C++ 函数类型自动转化 与二义性【成功就匹配,不然就是错误】

函数传递过程中, 参数 如果是基本类似,发生自动转换。

问题来源:4.编译器在当前的名字空间中找到与所求名字同名的实体之间进行决议(函数重载),如果选不出最优,就产生二义性错误

https://blog.nowcoder.net/n/bb65a484a87d4a7fab967d0555f6a152
1 int get(int m){
2     return m;
3 }
4  
5 long get(long m){
6     return m;
7 }
//double d = 1.234;
//调用get(d);double既可以隐式转换未long,也可以是int,
//或者说一般的数值类型之间都可以进行隐式类型转换,
//故无法确定那一个更加匹配。

函数传递过程中, 参数 如果是类 发生切割转换

  • C.145: Access polymorphic objects through pointers and references C.146: Use dynamic_cast where class hierarchy navigation is unavoidable
C.hier-access: Accessing objects in a hierarchy

Reason 

If you have a class with a virtual function, 

you don’t (in general) know which class provided the function to be used.



Example
struct B { 
   int a; virtual int f(); 
  virtual ~B() = default 
};

struct D : B { int b; int f() override; };

void use(B b)
{
    D d;
    B b2 = d;   // slice ??? 这地方怎么发生切换了呢
    B b3 = b;
}

void use2()
{
    D d;
    use(d);   // slice
}
Both ds are sliced.

Exception 


You can safely access a named polymorphic object in the scope of its definition, just don’t slice it.

void use3()
{
    D d;
    d.f();   // OK
}
See also 

A polymorphic class should suppress copying Enforcement Flag all slicing.




C.130: For making deep copies of polymorphic classes prefer a virtual clone function instead of public copy construction/assignment

Reason

Copying a polymorphic class is discouraged due to the slicing problem, see C.67. If you really need copy semantics, copy deeply: Provide a virtual clone function that will copy the actual most-derived type and return an owning pointer to the new object, and then in derived classes return the derived type (use a covariant return type)

.Example
class B {
public:
    virtual owner<B*> clone() = 0;
    
    B() = default;
    virtual ~B() = default;
    B(const B&) = delete; //禁用 
    
    B& operator=(const B&) = delete; //禁用 
};

class D : public B {
public:
    owner<D*> clone() override;
    ~D() override;
};

Generally, it is recommended to use smart pointers to represent ownership (see R.20). However, because of language rules, the covariant return type cannot be a smart pointer: D::clone can’t return a unique_ptrwhile B::clone returns unique_ptr. Therefore, you either need to consistently return unique_ptr in all overrides, or use owner<> utility from the Guidelines Support Library.

二、我不清楚的:重载 参数不一样呀?

2.1 疑问

多态:相同的方法调用可实现不同的实现方式,定义 重载 参数不一样呀?怎么算

多态分为四种:重载多态、强制多态、包含多态和参数多态。

重载多态分为两种:函数重载和运算符重载。

可以说,函数重载只是多态这个概念中非常小的一部分。

2.2 例子

//求距离 函数相同,参数相同 
template <class _InputIterator, class _Distance>
inline void distance(_InputIterator __first, 
                     _InputIterator __last, _Distance& __n)
{
  __STL_REQUIRES(_InputIterator, _InputIterator);
  __distance(__first, __last, __n, iterator_category(__first));
}


//参数 input_iterator_tag 不同
template <class _InputIterator, class _Distance>

inline void __distance(_InputIterator __first, _InputIterator __last,
                       _Distance& __n, input_iterator_tag)
{
  while (__first != __last) { ++__first; ++__n; }
}
//参数 random_access_iterator_tag 不同
template <class _RandomAccessIterator, class _Distance>
inline void __distance(_RandomAccessIterator __first, 
                       _RandomAccessIterator __last, 
                       _Distance& __n, random_access_iterator_tag)
{
  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  __n += __last - __first;
}



- 类型:
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

- iterator_traits

// The overloaded functions iterator_category, distance_type, and
// value_type are not part of the C++ standard.  (They have been
// replaced by struct iterator_traits.)  They are included for
// backward compatibility with the HP STL.

// We introduce internal names for these functions.

template <class _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{
  typedef typename iterator_traits<_Iter>::iterator_category _Category;
  return _Category();
}


// 特化版本一,针对原生指针类型
template <class _Tp>
struct iterator_traits<const _Tp*> {
  typedef random_access_iterator_tag iterator_category;
  typedef _Tp                         value_type;
  typedef ptrdiff_t                   difference_type;
  typedef const _Tp*                  pointer;
  typedef const _Tp&                  reference;
};


template <class _Iterator>
struct iterator_traits {
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};


template <class _Container>
class insert_iterator {
protected:
  _Container* container;
  typename _Container::iterator iter;
public:
  typedef _Container          container_type;
  typedef output_iterator_tag iterator_category;
  typedef void                value_type;
  typedef void                difference_type;
  typedef void                pointer;
  typedef void                reference;
  

60秒总结

一、 问:重载,重写 ,隐藏区别?

答:

  1. 重载 相同作用域内,函数名字相同,参数不同。
  2. 重写 不用作用域 , 函数名字相同,参数相同。
  3. 隐藏:不用作用域, 通过派生类访问:派生类同名函数,隐藏基类函数 或者通过基类指针访问,基类函数隐藏派生类。

二、 问题:如何解隐藏问题?

答:隐藏分为2个情况,同名函数查找过程 派生类 基类 全局

情况1 如果是通过派生类访问一个函数,派生类局部作用域隐藏上层 base同名函数。

  1. 为了让隐藏起来的名字重见天日,使用using声明
  2. 通过base类指针或者引用访问 (这个和虚函数无关)

情况2 如果是通过通过base类指针或者引用访问 隐藏派生类同名函数。

通过虚函数解决

三、 问 什么是多态?怎么实现的

答:

多态:同一个函数,不同的行为。具体选择那个行为 2个情况。

编译时的多态:函数重载和运算符重载(根据参数不同选择具体函数 )

运行时的多态:通过类继承和虚函数实现的(根据虚表指针 指向 派生类的函数,还是基类的函数)

四、 类型转换有几种情况,有什么区别?

答:

  1. 自动类型转换,缺点有可能丢失精度(派生类转换base类,3.14--3)
  2. 静态转换 动态转换 强制转换 和解释转换 3、 区别:转换类型 ,释放必须虚函数 ,安全与效率。

本文分享自微信公众号 - 架构说(JiaGouS),作者:王传义

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-07-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 数据库工程师常见面试题

    问题 1: 为什么 group by 和 order by 会使查询变慢? 答: group by 和 order by 操作通常需要创建一个临时表来处理查询...

    葆宁
  • OpenResty学习指南(一)

    我的博客: https://www.luozhiyun.com/archives/217

    luozhiyun
  • 多维度架构之超时时间

    超时时间俗称 Timeout 它是引起应用程序无响应或者网络服务雪崩灾难的罪魁祸首。

    netkiller old
  • 突破10万高并发的nginx性能优化经验 原

    转载:http://www.cnblogs.com/kevingrace/p/6094007.html

    拓荒者
  • 关于Nginx Web服务配置的一些优化

    开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理。

    后场技术
  • 面试官:换人!他连 TCP 这几个参数都不懂

    TCP 性能的提升不仅考察 TCP 的理论知识,还考察了对于操作系统提供的内核参数的理解与应用。

    小林coding
  • 【RL-TCPnet网络教程】第30章 RL-TCPnet之SNTP网络时间获取

    本章节为大家讲解RL-TCPnet的SNTP应用,学习本章节前,务必要优先学习第29章的NTP基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的效果。

    armfly
  • nginx优化 突破十万并发

    文章转载于:http://9388751.blog.51cto.com/9378751/1676821

    用户1214487
  • 【转】nginx优化 突破十万并发

    nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。

    流柯
  • TMQ微信沙龙第一期回顾

    Android流畅度原理&优化 活动时间:2016年5月26日 活动介绍:微信线上交流群活动介绍TMQ微信沙龙第一期分享圆满结束啦~本次分享的主题是Androi...

    腾讯移动品质中心TMQ
  • Kafka的灵魂伴侣Logi-KafkaManger(3)之运维管控--集群列表

    有想进滴滴LogI开源用户群的加我个人微信: jjdlmn_ 进群(备注:进群) 群里面主要交流 kakfa、es、agent、LogI-kafka-mana...

    石臻臻的杂货铺[同名公众号]
  • 显卡的帧率(FPS)、显示器刷新率和垂直同步的关系

    Zip
  • Nginx支持QUIC/HTTP3的实现路径和实践思考(内含ppt)

    https://http3-explained.haxx.se/en/why-quic/why-tcphol

    程序员小王
  • 性能,10点系统性思考

    作为一个半吊子全栈工匠,在20多年的职业生涯里遇到过太多关于软件性能的问题。论证或者证明性能的问题往往很关键,能否通过一次一个小而有逻辑的可证明可审核的步骤来解...

    半吊子全栈工匠
  • 微信小程序中将图片与音乐制作成MV

    最近一直在开发一个类似于小年糕的微信小程序,在开发制作MV功能时 ,花费了一些心思,其间主要遇到了以下一些问题点:

    越陌度阡
  • 大数据:大数据和数据可视化的重要性

    什么是大数据?数据可视化如何帮助企业更好地利用数据资源?一些人知道大数据的真正含义,然而其他人声称自己懂大数据,只是为了让他们看起来并不低人一等。尽管大数据是...

    灯塔大数据
  • Linux Linux内核参数调优

    2、尽量不要“批量”修改内核参数,笔者就曾这么干过,结果“调优”后,性能反而下降,事务出错数反而增加,所以,调优的时候可以考虑逐个参数进行调优,然后对比效果。

    授客
  • 为什么计算机起始时间是1970年1月1日?

    1970-01-01对于开发者来说都是不陌生的,有些系统对于时间的处理如果不够好的话,就可能把时间显示成1970-01-01,所以经常有用户看到1970-01-...

    程序IT圈
  • 漫话:为什么计算机起始时间是1970年1月1日?

    1970-01-01对于开发者来说都是不陌生的,有些系统对于时间的处理如果不够好的话,就可能把时间显示成1970-01-01,所以经常有用户看到1970-01-...

    帅地

扫码关注云+社区

领取腾讯云代金券