C++程序设计之兼谈对象模型

2023-05-16

前言

应具备的基础

  • 是上一篇博文“面向对象程序设计”的续集
  • 本文将探讨上文未讨论的主题

目标

  • 在先前培养正规、大器的编程素养上,继续探讨更多技术。
  • 泛型编程(Generic Programming)和面向对象编程(Object-Oriented Programming)虽然分属不同思维,但它们正是C++的技术主线。本文也讨论template(模板)。
  • 深入探索面向对象之继承关系(inheritance)所形成的对象模型(Object Model),包括隐藏于底层的this指针,vptr指针(虚指针),vtbl(虚表),virtual mechanism(虚机制),以及虚函数(virtual functions)造成的polymorphism(多态)效果。

将获得的代码

Test-Cpp.cpp

C++编译器

  • 编译(compile)
  • 连接(link)

conversion function, 转换函数

class Fraction
{
public:
    Fraction(int num, int den=1):m_numerator(num), m_denominator(den) { }
    operator double() const
    {
        return (double)(m_numerator / m_denominator)
    }
private:
    int m_numerator;//分子
    int m_denominator;//分母
};

使用:

Fraction f(3, 5);
double d = 4 + f;//调用operator double()将f转为0.6

non-explicit-one-argument ctor

class Fraction
{
public:
    Fraction(int num, int den=1):m_numerator(num), m_denominator(den) { }

    Fraction operator+(const Fraction& f)
    {
        return Fraction(......);
    }
private:
    int m_numerator;
    int m_denominator;
};

使用:

Fraction f(3, 5);
Fraction d2 = f + 4;//调用non-explicit ctor将4转为Fraction(4, 1),然后调用operator+

conversion function vs. non-explicit-one-argument ctor

class Fraction
{
public:
    Fraction(int num, int den=1):m_numerator(num), m_denominator(den) { }
    operator double() const
    {
        return (double) (m_numerator / m_denominator);
    }
    Fraction operator+(const Fraction& f)
    {
        return Fraction(......);
    }
private:
    int m_numerator;
    int m_denominator;
};

使用:

Fraction f(3, 5);
Fraction d2 = f + 4;//[ERROR]ambiguous 二义

explicit-one-argument ctor

class Fraction
{
public:
    explicit Fraction(int num, int den=1):m_numerator(num), m_denominator(den) { }
    operator double() const
    {
        return (double) (m_numerator / m_denominator);
    }
    Fraction operator+(const Fraction& f)
    {
        return Fraction(......);
    }
private:
    int m_numerator;
    int m_denominator;
};

使用:

Fraction f(3, 5);
Fraction d2 = f + 4;//[ERROR]conersion from 'double' to 'Fraction' requested

conversion function, 转换函数
proxy

template<class Alloc>
class vector<bool, Alloc>
{
public:
    typedef __bit_reference reference;
protected:
    reference operator[] (size_type n)
    {
        return *(begin() + difference_type(n));
    }
...
struct __bit_reference
{
    unsigned int* p;
    unsigned int mask;
    ...
public:
operator bool() const {return !(!(*p & mask)); }
...

pointer-like classes, 关于智能指针

template<class T>
class shared_ptr
{
public:
    T& operator*() const
    {return *px;}

    T* operator->() const
    {return px;}

    shared_ptr(T* p):px(p) { }

private:
    T* px;
    long* pn;
...
};

使用:

struct Foo
{
    ...
    void method(void) {......}
};
shared_ptr<Foo> sp(new Foo);

Foo f(*sp);

sp->method();

相当于

px->method();

pointer-like classes, 关于迭代器

template<class T, class Ref, class Ptr>
struct __list_iterator
{
    typedef __list_iterator<T, Ref, Ptr> self;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    link_type node;
    bool operator==(const self& x) const {return node == x.node; }
    bool operator!=(const self& x) const { return node != x.node; }
    reference operator*() const { return {*node}.data; }
    pointer operator->() const { return &(operator*());}
    self& operator++() { node = (link_type)((*node).next); return *this;}
    self operator++(int) { self tmp = *this; ++*this; return tmp;}
    self& operator--() { node = (link_type)((*node).prev); return *this;}
    self operator--(int) { self tmp = *this; --*this; return tmp; }
};

使用:

list<Foo>::iterator ite;
...
*ite;//获得一个Foo object
ite->method();
//意思是调用Foo::method()
//相当于(*ite).method();
//相当于(&(*ite))->method();

funciton-like classes, 所谓仿函数

template <class T>
struct identity
{
    const T&
    operator() (const T& x) const { return x; }
};

template <class Pair>
struct select1st
{
    const typename Pair::first_type&
    operator() (const Pair& x) const
    { return x.first; }
};

template <class Pair>
struct select2nd
{
    const typename Pair::second_type&
    operator() (const Pair& x) const
    { return x.second; }
};
template <class T1, class T2>
struct pair
{
    T1 first;
    T2 second;
    pair() : first(T1()), second(T2()) {}
    pair(const T1& a, const T2& b): first(a), second(b) {}
......
};

标准库中仿仿函数的奇特模样

template <class T>
struct identity : public unary_function<T, T>
{
    const T&
    operator() (const T& x) const { return x; }
};

template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type>
{
    const typename Pair::first_type&
    operator() (const Pair& x) const
    { return x.first; }
};

template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type>
{
    const typename Pair::second_type&
    operator() (const Pair& x) const
    { return x.second; }
};
template <class T>
struct plus : public binary_function<T, T, T>
{
    T operator()(const T& x, const T& y) const { return x + y; }
};
template <class T>
struct minus : public binary_function<T, T, T>
{
    T operator()(const T& x, const T& y) const { return x - y; }
};
template <class T>
struct equal_to : public binary_function<T, T, bool>
{
    T operator()(const T& x, const T& y) const { return x == y; }
};
template <class T>
struct plus : public binary_function<T, T, bool>
{
    T operator()(const T& x, const T& y) const { return x < y; }
};

标准库中,仿函数所使用的奇特的base classes

template <class Arg, class Result>
struct unary_function
{
    typedef Arg argument_type;
    typedef Result result_type;
};

template <class Arg1, class Arg2, class Result>
struct binary_function
{
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
};

less::result_type->bool

namespace经验谈

using namespace std;
//-----------------------------------
#include<iostream>
#include<memory>//share_ptr
namespace jj01
{
void test_member_template()
{ ...... }
}//namespace
//-----------------------------------
#include<iostream>
#include<list>
namespace jj02
{
template<typename T>
using Lst = list<T, allocator<T>>;
void test_template_template_param()
{ ...... }
}//namespace
//-----------------------------------

使用:

int main(int argc, char** argv)
jj01::test_member_template();
jj02::test_template_template();

class template, 类模板

template<typename T>
class complex
{
public:
    complex(T r = 0, T i = 0)
    : re(r), im(i)
    {}
    complex& operator += (const complex&);
    T real () const { return re; }
    T imag () const { return im; }
private:
    T re, im;

    friend complex& __doapl (complex*, const complex&);
};

使用:

{
    complex<double> c1(2.5, 1.5);
    complex<int> c2(2, 6);
    ...
}

function template, 函数模板

stone r1(2, 3), r2(3, 3), r3;
r3 = min(r1, r2);

编译器会对function template进行实参推导(argument deduction)

template <class T>
inline const T& min(const T& a, const T& b)
{
    return b < a ? b : a;
}

实参推导的结果,T为stone,于是调用stone::operator<

class stone
{
public:
    stone(int w, int h, int we) 
    : _w(w), _h(h), _weight(we)
    { }
    bool operator< (const stone& rhs) const
    { return _weight < rhs._weight; }
private:
    int _w, _h, _weight;
};

member template, 成员函数

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair()
        : first(T1()), second(T2()) {}
    pair(const T1& a, const T2& b)
        : first(a), second(b) {}
    template <class U1, class U2>
    pair(const pair<U1, U2>& p)
        : first(p.first), second(p.second) {}
};
class Base1{};
class Derived1:public Base1{};

class Base2{};
class Derived2:public Base2{};
pair<Derived1, Derived2>p;
pair<Base1, Base2>p2(p);
pair<Base1, Base2>p2(pair<Derived1, Derived2>());
template<typename _Tp>
class shared_ptr:public __shared_ptr<_Tp>
{
...
    template<typename _Tp1>
    explicit shared_ptr(_Tpl* __p)
    :__shared_ptr<_Tp>(__p){}
...    
};
Base1* ptr = new Derived1;//up-cast
shared_ptr<Base1>sptr(new Derived1);//模拟up-cast

specialization, 模板特化

【注】特化反义词:泛化

泛化

template <class Key>
struct hash{ };

特化

template<>
struct hash<char>
{
    size_t operator() (char x) const { return x; }
};

template<>
struct hash<int>
{
    size_t operator() (int x) const { return x; }
};

template<>
struct hash<long>
{
    size_t operator() (long x) const { return x; }
};

使用:

cout << hash<long>() (1000);

泛化又叫full specialization,全泛化,对应偏特化。

patial specialization, 模板偏特化——个数的偏

template<typename T, typename Alloc=...>
class vector
{
    ...
};

绑定

template<typename Alloc=...>
class vector<bool, Alloc>
{
    ...

patial specialization, 模板偏特化——范围的偏

template <typename T>
class C
{
    ...
};

【注】上下的T不是一个T

template <typename T>
class C<T*>
{
    ...
};

这样写也可以

template <typename U>
class C<U*>
{
    ...
};

使用:

C<string> obj1;
C<string*> obj2;

template template parameter, 模板模板参数

template<typename T, 
        template <typename T>
            class Container
        >
class XCls
{
private:
    Container<T> c;
public:
    ......
};
template<typename T>
using Lst = list<T, allocator<T>>;
XCls<string, list> mylst1;//错误
XCls<string, Lst> mylst2;
template<typename T,
            template <typename T>
                class SmartPtr
        >
class XCls
{
private:
    SmartPtr<T> sp;
public:
    XCls():sp(new T) { }
};
XCls<string, shared_ptr> p1;
XCls<string, unique_ptr> p2;//错误
XCls<int, weak_ptr> p3;//错误
XCls<long, auto_ptr> p4;

这不是template template parameter

template <class T, class Sequence = deque<T>>
class stack
{
    friend bool operator== <> (const stack&, const stack&);
    friend bool operator< <> (const stack&, const stack&);

protected:
    Sequence c;//底层容器
......
};

使用

stack<int> s1;
stack<int, list<int>> s2;

关于C++标准库

容器

Sequence containers

array
vector
deque
forward_list
list

Container adaptors

stack
queue
priority_queue

Associative containers

set
multiset
map
multimap

Unordered associative con

unordered_set
unordered_multiset
unordered_map
unordered_multimap

算法

Sorting

sort
stable_sort
partial_sort
partial_sort_copy
is_sorted
is_sorted_until
nth_element

Binary search

lower_bound
upper_bound
equal_range
binary_search

Merge

merge
inplace_merge
includes
set_union
set_intersection
set_difference
set_symmetric_difference

推书:Algorithms + Data Structures = Programs(Niklaus Wirth)

确认支持C++11: macro __cplusplus
测试:
VS2012

#include"stdafx.h"
#include <iostream>
using namespace std;

int main()
{
    cout<<__cplusplus<<endl;
    return 0;
}

Dev-C++ 5

#include <iostream>

int main()
{
    std::cout<<__cplusplus;
}

如果是199711,则不支持C++11,需修改编译器
如果是201103,则支持C++11

variadic templates(since C++11) 数量不定的模板参数

void print()
{
}

template<typename T, typename... Types>
void print(const T& firstArg, const Type&... args)
{
    cout<<firstArg<<endl;
    print(args...);
}

Inside variadic templates, sizeof…(arg) yields the number of arguments

…就是一个所谓的pack(包)
用于template parameters, 就是template parameters pack(模板参数包)
用于function parameter types, 就是function parameter types pack(函数参数类型包)
用于function parameters, 就是function parameters pack(函数参数包)

使用:

print(7.5, "hello", bitset<16>(377), 42);

结果:

7.5
hello
0000000101111001
42

auto(since C++11)

过去:

list<string> c;
...
list<string>::iterator ite;
ite = find(c.begin(), c.end(), target);

现在:

list<string> c;
...
auto ite = find(c.begin(), c.end(), target);

错误:

list<string> c;
...
auto ite;//错误
ite = find(c.begin(), c.end(), target);

ranged-base for(since C++11)

for(decl : coll)
{
    statement
}
for(int i : {2, 3, 5, 7, 9, 13, 17, 19})
{
    cout<< i << endl;
}
vector<double> vec;
...
for(auto elem : vec)//pass by value
{
    cout << elem << endl;
}

for(auto& elem : vec)// pass by reference
{
    elem *= 3;
}

reference

int x=0;
int* p = &x;
int& r = x;//r代表x。现在r,x都是0
int x2 = 5;

r = x2;//r不能重新代表其他物体。现在r,x都是5
int& r2 = r;//现在r2是5(r2代表r:亦相当于代表x)

从内存上看,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWdLqDZF-1634388189033)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——reference.png?raw=true)]

注意:

  1. sizeof® == sizeof(x)
  2. &x = &r;

object和其reference的大小相同,地址也相同(全都是假象)
Java里头所有变量都是reference

typedef struct Stag{int a, b, c, d;} S;
int main()
{
    double x = 0;
    double* p = &x;//p指向x,p的值是x的地址
    double& r = x;//r代表x,现在r,x都是0

    cout << sizeof(x) << endl;//8
    cout << sizeof(p) << endl;//4
    cout << sizeof(r) << endl;//8
    cout << p << endl;//0065FDFC
    cout << *p << endl;//0
    cout << x << endl;//0
    cout << r << endl;//0
    cout << &x << endl;//0065FDFC
    cout << &r << endl;//0065FDFC

    S s;
    S& rs = s;
    cout << sizeof(s) << endl;//16
    cout << sizeof(rs) << endl;//16
    cout << &s << endl;//0065FDE8
    cout << &rs << endl;//0065FDE8
    }

object和其reference的大小相同,地址也相同(全都是假象)

reference的常见用途

void func1(Cls* pobj) {pobj->xxx();}
void func2(Cls obj) {obj.xxx();}被调用端 写法相同,很好
void func3(Cls& obj) {obj.xxx();}//被调用端 写法相同,很好
......
Cls obj;
func1(&obj);//接口不同,困扰
fun2(obj);//调用端接口相同,很好
func3(obj);//调用端接口相同,很好

reference通常不用于声明变量,而用于参数类型(parameters type)和返回类型(return type)的描述。

以下被视为"same signature"(所以二者不能同时存在):

double imag(const double& im) {...}
double imag(const double im) {...}  //Ambiguity

【注】imag(const double& im)为signature, 不含return type.
imag(const double& im)后面可以加const, const是函数签名的一部分。
所以imag(const double& im)和imag(const double& im) const两个函数可以并存。

对象模型(Object Model):关于vptr 和 vtbl

class A
{
public:
    virtual void vfunc1();
    virtual void vfunc2();
            void func1();
            void func2();
private:
    int m_data1, m_data2;
};
class B:public A
{
public:
    virtual void vfunc1();
            void func2();
private:
    int m_data3;
};
class C:public B
{
public:
    virtual void vfunc1();
            void func2();
private:
    int m_data1 m_data4;
};

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0UWljrYa-1634388189038)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——关于vptr和vtbl.png?raw=true)]

对象模型(Object Model):关于this

Template Method
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNGEvAi6-1634388189041)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——关于this.png?raw=true)]

再谈const

const object(data members不得变动)  non-const object(data members可变动)
const member functions
(保证不更改data members)           √                √
non-const member functions
(不保证data members不变)           ×                √

当成员函数的const和non-const版本同时存在,const object只会(只能)调用const版本,non-const object只会(只能)调用non-const版本。

const String str("hello world");
str.print();

如果当初设计string::print()时未指明const,那么上行便是经由const object调用non-const member function,会出错。此非所愿。

non-const member functions可调用const member functions,反之则不行,会引发:

(VC)error C2662:cannot convert 'this' pointer from 'const class X' to 'class X &'.Conversion loses qualifiers

class template std::basic_string<…>有如下两个member functions:

charT
operator[](size_type pos) const
{....../*不必考虑COW*/}

reference
operator[](size_type pos)
{....../*必须考虑COW*/}

COW:Copy On Write

对象模型(Object Model):关于Dynamic Binding

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DeWrJbt1-1634388189045)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——静态绑定.png?raw=true)]

动态绑定三个条件:

  1. 通过指针
  2. 虚函数
  3. 向上转型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwVvzrIv-1634388189049)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——动态绑定.png?raw=true)]

再谈new和delete

::operator new, ::operator delete, ::operator new[], ::operator delete[]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjntHq3a-1634388189051)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——new&delete.png?raw=true)]

重载member operator new/delete

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U1rWQgaE-1634388189056)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——重载.png?raw=true)]

重载member operator new[]/delete[]

和上图的区别在于多了一个[]

class Foo
{
public:
    void* operator new[](size_t);
    void operator delete[](void*, size_t);
};

示例, 接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yQKFNQIv-1634388189058)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——示例.png?raw=true)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ywNawNvp-1634388189061)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——示例2.png?raw=true)]
int 4字节,long 4字节,string(里面是个指针)4字节
有虚函数就多一个指针(12+4=16)

Foo[5] 数组,有5个,12*5=60,第一个记录有5个元素,这个记录的size为4,60+4=64
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dpNQINe-1634388189063)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——示例3.png?raw=true)]

重载new(), delete()

我们可以重载class member operator new(),写出多个版本,前提是每一个版本的声明都必须有独特的参数列,其中第一参数必须是size_t,其余参数以new所指定的placement arguments为初值。出现于new(…)小括号内的便是所谓placement arguments。

Foo* pf = new(300, 'c') Foo;

我们也可以重载class member operator delete()(或称此为placement operator delete),写出多个版本,但它们绝不会被delete调用。只有当new所调用的ctor抛出exception,才会调用这些重载版的operator delete()。它只可能这样被调用,主要用来归还未能完全创建成功的object所占用的memory。

示例

class Foo
{
public:
    Foo(){cout<<"Foo::Foo()" << endl; }
    Foo(int){cout << "Foo::Foo(int)" << endl; throw Bad();}//class Bad{};
    //故意在这儿抛出exception,测试placement operator delete.s

    //(1)这里就是一般的operator new()的重载
    void* operator new(size_t size)
    {
        return malloc(size);
    }

    //(2)这个就是标准库已提供的placement new()的重载(的形式),(所以此处也模拟standard placement new,就只是传回pointer)
    void* operator new(size_t size, void* start)
    {
        return start;
    }

    //(3)这个才是崭新的palcement new
    void* operator new(size_t size, long extra)
    {
        return malloc(size+extra);
    }

    //(4)这又是一个placement new
    void* operator new(size_t size, long extra, char init)
    {
        return malloc(size+extra);
    }

    //(5)这又是一个placement new, 但故意写错第一参数的type(那必须是size_t以符合正常的operator new)
    //void* operator new(long extra, char init)
    //{
    //    [Error]'Operator new' takes type 'size_t'('unsigned int') as first parameter[-fpermissive]
    //    return malloc(extra);
    //}

    //以下是搭配上述placement new的各个所谓placement delete.
    //当ctor发出异常,这儿对应的operator(placement) delete就会被调用.
    //其用于是释放对应之placement new分配所得的memory.
    //(1)这儿就是一般的operator delete()的重载
    void operator delete(void*,size_t)
    {cout << "operator delete(void*, size_t)" << endl;}

    //(2)这是对应的(2)
     void operator delete(void*,void*)
    {cout << "operator delete(void*, void*)" << endl;}  
    
    //(3)这是对应的(3)
     void operator delete(void*, long)
    {cout << "operator delete(void*, long)" << endl;}  

    //(4)这是对应的(4)
     void operator delete(void*, long, char)
    {cout << "operator delete(void*, long, char)" << endl;}

private:
    int m_i;
};

测试代码:

Foo start;
Foo* p1 = new Foo;
Foo* p2 = new(&start) Foo;
Foo* p3 = new(100) Foo;
Foo* p4 = new(100,'a') Foo;
Foo* p5 = new(100) Foo(1);//ctor抛出异常
Foo* p6 = new(100,'a') Foo(1);
Foo* p7 = new(&start) Foo(1);
Foo* p8 = new Foo(1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Vk6HPpv-1634388189066)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——test.png?raw=true)]

ctor抛出异常,但G4.9没调用operator delete(void*, long),但G2.9确实调用了。

即使operator delete(…)未能一一对应于operator new(…),也不会出现任何报错。意思是:放弃处理ctor发出的异常。

basic_string使用new(extra)扩充申请量

用于是释放对应之placement new分配所得的memory.
//(1)这儿就是一般的operator delete()的重载
void operator delete(void*,size_t)
{cout << “operator delete(void*, size_t)” << endl;}

//(2)这是对应的(2)
 void operator delete(void*,void*)
{cout << "operator delete(void*, void*)" << endl;}  

//(3)这是对应的(3)
 void operator delete(void*, long)
{cout << "operator delete(void*, long)" << endl;}  

//(4)这是对应的(4)
 void operator delete(void*, long, char)
{cout << "operator delete(void*, long, char)" << endl;}

private:
int m_i;
};

测试代码:
```cpp
Foo start;
Foo* p1 = new Foo;
Foo* p2 = new(&start) Foo;
Foo* p3 = new(100) Foo;
Foo* p4 = new(100,'a') Foo;
Foo* p5 = new(100) Foo(1);//ctor抛出异常
Foo* p6 = new(100,'a') Foo(1);
Foo* p7 = new(&start) Foo(1);
Foo* p8 = new Foo(1);

[外链图片转存中…(img-7Vk6HPpv-1634388189066)]

ctor抛出异常,但G4.9没调用operator delete(void*, long),但G2.9确实调用了。

即使operator delete(…)未能一一对应于operator new(…),也不会出现任何报错。意思是:放弃处理ctor发出的异常。

basic_string使用new(extra)扩充申请量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwxPYzi8-1634388189070)(https://github.com/hubojing/BlogImages/blob/master/C++程序设计之兼谈对象模型——basic_string.png?raw=true)]

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++程序设计之兼谈对象模型 的相关文章

  • ChatGPT自我分析

    作者 xff1a chatgpt ChatGPT 是一个由 GPT 技术驱动的聊天机器人 xff0c 它能够回答各种问题 提供信息和建议 生成文本和完成其他任务 ChatGPT 是一个深度学习模型 xff0c 是人工智能技术中的一种 在本博
  • Visutal Studio2022 如何使用Github copilot

    visual studio 2019 升级最新版本的2019也并没有搜索到 xff0c 直接升级到visual studio 2022 xff0c 看发布介绍也是2022的copilot Copilot 是一款由 OpenAI 开发的基于
  • 音视频领域的经典书籍推荐

    数字视频处理基础 xff08 Digital Video Processing xff09 xff1a 作者A Murat Tekalp xff0c 讲述数字视频处理的基本概念和技术 xff0c 包括视频编码 图像分析 视频通信和多媒体系统
  • 音视频专家

    作为一名顶级的音视频专家 xff0c 需要在音视频领域拥有非常深入的技术理解和丰富的实践经验 xff0c 并且要能够在行业内产生深远的影响和贡献 以下是更详细的顶级音视频专家提升计划 xff1a 1 深入研究音视频核心技术 作为顶级音视频专
  • 2022年新兴技术趋势

    图片源自 xff1a 2022年Gartner新兴技术成熟度曲线公布最新技术趋势 Gartner中国 人工智能和机器学习技术仍处于高峰 xff0c 但已经开始进入成熟期 这表明人工智能和机器学习技术已经不再是新颖的概念 xff0c 而是逐渐
  • 白镜1-1

    2029年 xff0c 人类社会已经进入了全球化 数字化 智能化的新时代 xff0c 各国政府和企业已经开始在深海和太空等地方进行勘探和开采 同时 xff0c 在不断提升的科技水平下 xff0c 人类已经开始了向宇宙的探索和移民 在这样一个
  • Jetson查看GPU显存信息

    pip3 install jetson stats jtop 然后运行jtop命令即可 xff0c jetson xavier nx 的查看命令并不是nvidia smi xff0c 所以运行nvidia smi并没有效果 xff01 效果
  • 并不包含调试信息(未加载任何符号)

    今天调试一C 43 43 程序 xff0c 按下F5 xff0c 老是弹出一对话框显示信息 xff1a debugging information for 39 myproject exe 39 cannot be found or doe
  • hdu 1358 Period KMP

    题目大意 xff1a 对于一个字符串 xff0c 找由循环字符串组成的位置 xff0c 并输出最多循环了几次 xff0c 比如两个样例 xff0c 第一个是 aaa xff0c 所以在第二个位置由子串a循环两次得到 xff0c 第三个位置由
  • mysql max_connections 最大连接数,用户数

    设置max connections xff08 这个办法在debian xff0b mysql Ver 12 22 Distrib 4 0 22 for pc linux i386 里实验了 xff09 设置办法是在my cnf文件中 xf
  • dll文件加载运行加载的14001错误,由于应用程序配置不正确,应用程序未能启动

    最近在处理项目问题的的时候发现了这么一个问题 xff0c 就是我们的程序在调用第三方提供的dll文件的时候在一台机器上面会报14001的错误 xff0c 但是在另一台机器上面不会 两台机器上面的操作系统是相同的 针对这个问题和这个错误码 x
  • Python框架下django 的并发和多线程

    django 的并发能力真的是令人担忧 xff0c django本身框架下只有一个线程在处理请求 xff0c 任何一个请求阻塞 xff0c 就会影响另一个情感求的响应 xff0c 尤其是涉及到IO操作时 xff0c 基于框架下开发的视图的响
  • Linux查看电源状态指令

    dmidecode命令可以让你在Linux系统下获取有关硬件方面的信息 dmidecode的作用是将DMI数据库中的信息解码 xff0c 以可读的文本方式显示 由于DMI信息可以人为修改 xff0c 因此里面的信息不一定是系统准确的信息 d
  • HashCode()和equals()的区别

    文章目录 HashCode简介equals简介1 类中重写HashCode和equals方法比较两个对象是否相等2 HashSet保证元素的唯一性 HashCode简介 hashCode 方法的作用是获取哈希码 xff0c 返回的是一个in
  • 远算CAE平台-基于云平台的Hypermesh与Abaqus联合仿真(轴承底座)

    小编在这里展示一个Hypermesh与Abaqus的联合仿真案例 xff1a 本次联合仿真使用Hypermesh进行前处理 xff0c 然后在Abaqus中设置并计算 xff0c 最后使用Hyperview查看结果 1 在Hypermesh
  • ubuntu OPT权限

    首先opt是系统文件夹 xff0c 权限被保护起来了需要一定的权限才可以操作 1 打开终端 输入如下命令 2 sudo chmod 777 opt 然后回车 xff0c 这时候会提示输入管理员密码密码 xff0c 这样opt就可以创建文件了
  • 看这篇就够了——ubuntu系统中的cuda cudnn cudatookit及pytorch使用

    一 基本概念 1 1 nvidia独立显卡 独立显卡是指以独立板卡形式存在 xff0c 可在具备显卡接口的主板上自由插拔的显卡 独立显卡具备单独的显存 xff0c 不占用系统内存 xff0c 而且技术上领先于集成显卡 xff0c 能够提供更
  • 虚拟机中ubuntu系统无法正常连接网络

    网络连接标志不见 xff0c 或者链接状态无 xff0c 或者如下图 解决办法1 xff1a 桥连接模式 桥连接模式就是直接使用物理主机的网络 假设物理主机在局域网中 xff0c IP地址为192 168 20 24 24 xff0c 因此
  • golang interface 使用

    interface 是方法签名的集合 xff0c interface 类型的值可以存储任何类型变量的值的类型 学到的一个问题 xff0c 判断 interface 类型的变量不能只判断 value xff0c 需要判断 type 和 val
  • 前端自动化构建工具搭建基于Ubuntu20.04:第五步ssh免密登录

    jenkins服务器与前端资源运行服务器之间实现免密登录 jenkins服务器 A 前端资源运行服务器 B 生成ssh密钥 span class token comment 邮箱信息根据自己情况选择 一路回车生成下面的图片内容 span s

随机推荐

  • 常用图算法(C语言)

    最短路 Dijkstra 题目 xff1a 743 网络延迟时间 邻接矩阵 xff1a span class token keyword int span span class token function min span span cl
  • POJ初级分类 贪心专题 poj1328 POJ2109 POJ 2586

    题目1328 代码及解释 xff1a POJ1328 Radar Installation 题目大意 xff1a 有一条海岸线 xff0c 一边是海岸 xff0c 一边是大海 xff1b 海中有一些小岛 xff0c 我们要建造一些雷达 xf
  • 离散数学第六章 图

    图 一 图的基本概念 1 无向图与有向图 此处要熟悉一下无序对与无序积的概念 xff1b 集合中有元素重复出现的话就称为多重集合 xff0c 简称多重集 xff0c 元素在多重集合中出现的次数称为该元素的重复度 xff1b 无向图 xff1
  • 最佳加法表达式(动态规划)

    递归 xff08 带备忘的自顶向下法 xff09 题目 xff1a 有一个由1 9组成的数字串 问如果将m个加 号插入到这个数字串中 在各种可能形成的 表达式中 xff0c 值最小的那个表达式的值是多少 子问题 xff1a 将最后面的那个加
  • 常见排序代码(C语言)

    选快希堆不稳 xff08 是不稳定的排序 xff09 xff0c 堆归选基不变 xff08 运行时间不发生变化 xff0c 与初始状态无关 xff09 插入排序 Note The returned array must be malloce
  • PyCharm安装第三方模块Request、BeautifulSoup

    开始用eclipse写python xff0c 然后还是不怎么好用 xff0c 当初本地装了BeautifulSoup模块 xff0c eclipse里面也不能用 xff0c python自带IDLE也不是很好用 xff0c 就又转PyCh
  • MySQL的join用法

    MySQL的join用法主要有三种 xff1a inner jon 内连接left join 左连接right join 右连接 table a table b 1 inner join 内连接又叫等值连接 xff0c 此时的inner可以
  • OpenCV VideoWriter用法

    百度了一些 xff0c 发现不对 xff0c 在stackoverflow上面找到了解决方法 xff0c 好像是版本问题 import cv2 path 61 span class hljs string 34 34 span file 6
  • Vue 项目部署到阿里云服务器(Nginx 代理)

    查看 linux 服务器版本号 lsb release a 1 本地打包 首先 xff0c 要将本地 config index js 中的 assetsPublicPath 39 39 改为 assetsPublicPath 39 39 x
  • 一种跨平台的C/C++动态库的符号隐藏方式

    源地址 xff1a http blog guorongfei com 2018 04 11 symbol visibility lt h1 id 61 34 什么是符号隐藏 34 gt lt a href 61 34 什么是符号隐藏 34
  • 如何在vscode使用 Copilot、Sign in to access the GitHub Copilot technical preview.

    1 Copilot申请方法 使用浏览器打开如下链接 xff1a https copilot github com 2 点击Sign up xff0c 登录你的GitHub账号 3 点击Join Waitlist xff0c 加入候补名单 4
  • 将QImage转化为半透明的效果

    之前项目上的需要 xff0c 中间用到了把QImage变成半透明的效果 xff0c 当时查了一些资料 xff0c 为了防止遗忘 xff0c 就在博客中记录了下来 下面是代码 xff1a 将QImage转化为半透明的效果 QPixmap Ch
  • 快速实现内网穿透已成功(巧妙绕过路由器)

    内网穿透在实际生活中 xff0c 我们经常会在内网里部署服务让外网访问内网应用 xff0c 比如Apache xff0c Tomcat xff0c 数据库 xff0c 微信小程序的开发以及企业的一些管理软件 xff08 OA CRM ERP
  • Kali更新源

    若在apt get install update有报错的情况 xff1a 则需要更换kali的源了 更换方法 vim etc apt sources list d docker list 或 vim ect apt sources list
  • python使用pytesseract识别验证码的方法

    1 系统环境 OS X 10 7 MacBook Pro 13英寸 xff0c 2012年初期 Python 2 7 2 需要软件包 a 需要安装PIL以及pytesseract库 Python tesseract是一个基于google 3
  • WebService的简单案例记录(Java)

    关于WebService xff0c 工作关系 xff0c 断断续续有接触到一些 xff0c 写完就忘 xff0c 下次要写又不记得 所以做个简单的案例 xff0c 啥时候忘了能查一查 酱紫 xff0c 先大概讲一下我理解的WebServi
  • 阿里云使用之ECS安全组

    ECS是什么 云服务器 ECS是阿里云提供的云服务器 xff0c 是一种弹性可伸缩的计算服务 xff0c 助您降低 IT 成本 xff0c 提升运维效率 xff0c 使您更专注于核心业务创新 防火墙的痛点 由于使用了云服务 xff0c 随着
  • 在linux上安装CMake

    在linux上安装CMake 一 下载CMake安装包二 配置环境变量三 验证是否能执行CMake四 CMake官方文档 一 下载CMake安装包 本文演示环境为Linux系统 xff0c Redhat7 64位 CMake提供了两种安装方
  • Microsoft 365 E5 开发者如何添加新用户

    Microsoft 365 E5 开发者如何添加新用户 登录进入Microsoft 365 管理员中心 https admin microsoft com Adminportal Home source 61 applauncher hom
  • C++程序设计之兼谈对象模型

    前言 应具备的基础 是上一篇博文 面向对象程序设计 的续集本文将探讨上文未讨论的主题 目标 在先前培养正规 大器的编程素养上 xff0c 继续探讨更多技术 泛型编程 Generic Programming 和面向对象编程 Object Or