[C ++] palavras-chave estáticas, virtuais e const

As funções de membro estáticas podem ser declaradas como const?

Não posso. A função de membro estático pertence à classe e pode ser acessada diretamente pelo nome da classe. Ela não pertence a nenhum objeto e o ponteiro this não será colocado no acesso.

No entanto, funções-membro const adicionarão um const this * implícito quando acessadas e seu uso é conflitante.


As funções de membro estático podem ser declaradas virtuais?

Não posso. As funções de membro estáticas têm apenas um código para cada classe e não há necessidade de ligação polimórfica.


Por que C ++ não oferece suporte ao construtor como uma função virtual?

A função virtual é acessada por meio do ponteiro virtual vptr, que é inicializado por meio do construtor. Se o construtor for uma função virtual, o que significa que vptr não pode ser gerado, ele cairá em um paradoxo.


http://legendtkl.com/2014/09/30/cplusplus-static-and-virtual/

Primeiramente, deixe-me declarar que este não é um tutorial introdutório, desde que você entenda a função da estática e o mecanismo de implementação de funções virtuais em C ++. :)

Deixe-me começar com algumas perguntas. Pense um pouco. O destruidor de uma classe pode ser virtual? O construtor de uma classe pode ser virtual? O construtor de uma classe pode ser estático? O destruidor de uma classe pode ser estático? As funções virtuais podem ser estáticas?

A função da palavra-chave estática pode ser simplesmente resumida como: quando aplicada a variáveis ​​globais, quando aplicada a variáveis ​​locais, quando aplicada a funções e quando aplicada a classes em C ++. Existem muitos dos três primeiros tipos de escrita. Hoje, escrevo principalmente quando a estática é aplicada a classes C ++, bem como palavras-chave virtuais.

O uso de estático em classes é simplesmente de dois tipos: membros de dados estáticos e funções de membro estático.

O membro de dados estáticos é proposto pelo compilador e pela classe e é considerado uma variável global, mas apenas visível no escopo de vida da classe. Cada membro de dados estáticos possui apenas uma entidade, que é armazenada no segmento de dados do programa. Você pode usar static para modificar variáveis ​​locais para comparação e compreensão. Embora o acesso possa ser chamado pelo operador '.', Não é necessário, ou seja, pode ser chamado pelo operador de escopo "::". Por exemplo, a classe A possui um membro de dados estáticos z que pode ser chamado por A :: z. É importante notar que os membros de dados estáticos da classe devem ser definidos globalmente antes que possam ser usados. Caso contrário, o compilador reportará um erro: referência indefinida. Em outras palavras, membros estáticos são declarados na classe e são invisíveis de fora.

Antes de falar sobre funções de membro estáticas, vamos falar sobre como chamar funções de membro. Vamos falar sobre funções de membro não estáticas primeiro. Para garantir que as funções de membro não estáticas sejam pelo menos tão eficientes quanto as funções externas gerais, o compilador reescreverá funções de membro não estáticas em funções gerais. As principais etapas de conversão são as seguintes:

  1. Reescreva o protótipo da função e insira um parâmetro adicional neste ponteiro para fornecer um canal de acesso para o objeto de classe chamar a função.
  2. As operações de acesso a membros de dados não estáticos da classe no corpo da função são alteradas para acesso por meio do ponteiro this.
  3. Reescreva a função de membro como uma função externa e "mutile" o nome da função para evitar conflitos de símbolo.
    Um exemplo é o seguinte:
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
    11 
    12 
    13 
    14 
    15 
    16 
    17 
    18 
    19 
    20 
    21
    
    class Legend {
              
             
    private : 
    int x; int y; int z; public :     legend () {}     ~ legend () {} int sum () const {
              int ret = x + y + z; return ret;     } }; // 内部 转化void sum_3legendFv ( const legenda * const this , int & amp; __ result) {
              int ret = this - & gt; x + this - & gt; y + this - & gt; z;    
        
        
    
    
    
          
             
            
            
    
    
    
      
             
        
    
        __resultado = certo;
    
        return;
    }
    

感受一下思想,其中引入了NRV(named returned value),先不要太在意,知道有这个东西就好了。

虚成员函数是通过虚函数表来访问的。虚函数的实现机制简单来说就是,类为所有的虚函数建一个虚函数表vtbl,每个类只有一个。每个对象有一个虚函数表指针,vptr,通过指针来访问。因为访问说到底就是找到函数地址。之所以多态无法在编译器间确定,而要在运行时才能确定就是因为在编译器无法确定指针或者引用指向的真正的类型,从而无法确定偏移找到函数地址。

1
2
3
prt->normal()
//内部转化
(*ptr->vptr[1])(ptr)

其中vptr表示由编译器产生的指针,指向virtual table。1是virtual table slot的索引值,关联到normal函数,第二个ptr是this指针。

静态成员函数并不会关联到this指针,因此差不多等同于外部函数。主要有下面三个特性

  1. 不能直接存取其class内的非静态成员
  2. 不能够直接声明为const
  3. 不需要通过对象来调用。
    下面我们来看上面几个问题

1.类的析构函数可以为virtual吗?毋庸置疑,对于可能作为基类的类的析构函数要求就是virtual的。因为如果不是virtual的,派生类析构的时候调用的是基类的析构函数,而基类的析构函数只要对基类部分进行析构,从而可能导致派生类部分出现内存泄漏问题。

2.类的构造函数可以为virtual吗?答案也是不能的,通过上面虚函数的调用方式我们知道虚函数是通过vptr来访问的。那么vptr是怎么来的呢?vptr确定通过构造函数来初始化的。鸡生蛋,蛋生鸡,鸡生蛋……

3.类的构造函数可以为static吗?根据之前说的static不能访问非静态成员变量这点可以知道构造函数是不可以为static的。两者static是对应于每个类的,而构造函数主要负责初始化对象的。这里要提一下C#中的static构造函数是用于在使用类之前进行相关的初始化工作。比如,初始化静态成员或执行特定操作。CLR在第一次创建该类对象或调用该类静态方法时自动调用静态构造函数。

4.类的析构函数可以为static吗?同上。

5.virtual函数可以为static吗?答案是不可以。virtual函数和static函数访问方式是不一样。


内联函数,构造函数,静态函数都不能是虚函数

http://blog.csdn.net/love_gaohz/article/details/7534140

inline, static, constructor三种函数都不能带有virtual关键字。

inline是编译时展开,必须有实体;
static属于class自己的,也必须有实体;
virtual函数基于vtable(内存空间),constructor函数如果是virtual的,调用时也需要根据vtable寻找,但是constructor是virtual的情况下是找不到的,因为constructor自己本身都不存在了,创建不到class的实例,没有实例,class的成员(除了public static/protected static for friend class/functions,其余无论是否virtual)都不能被访问了。

 

 C++函数中那些不可以被声明为虚函数

常见的不不能声明为虚函数的有:普通函数(非成员函数);静态成员函数;内联成员函数;构造函数;友元函数。

1.为什么C++不支持普通函数为虚函数?

普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时邦定函数。

2.为什么C++不支持构造函数为虚函数?

这个原因很简单,主要是从语义上考虑,所以不支持。因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。(这不就是典型的悖论)

3.为什么C++不支持内联成员函数为虚函数?

其实很简单,那内联函数就是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。(再说了,inline函数在编译时被展开,虚函数在运行时才能动态的邦定函数)

4.为什么C++不支持静态成员函数为虚函数?

这也很简单,静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,他也没有要动态邦定的必要性。

5.为什么C++不支持友元函数为虚函数?

因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法

*********************************************************************

1.顶层函数:多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层函数不属于成员函数,是不能被继承的。

2.构造函数:(1)构造函数不能被继承,因而不能声明为virtual函数

                        (2)构造函数一般是用来初始化对象,只有在一个对象生成之后,才能发挥多态作用,如果将构造函数声明为virtual函数,则表现为在对象还没有生成的情况下酒使用了多态机制,因而是行不通的,如下例:

#include<iostream>
using namespace std;
class B
{
public:

B() {}
virtual void show() {cout<<"***"<<endl;}
};
class D:public B
{
public:

D() {}
void show() {cout<<"==="<<endl;}
};

int main()
{
B *pb;
D d; //先生成对象
pb=&d;
pb->show(); //再体现多态
pb=new D(); //先调用构造函数

pb->show(); //再多态
delete pb;
return 0;
}

3.static函数:不能被继承,只属于该类。

4.友元函数:友元函数不属于类的成员函数,不能被继承。

5.inline函数:inline函数和virtual函数有着本质的区别,inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够

确定如何去调用的,因而inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。此外,一切virtual函数都不可能是inline函数。


Acho que você gosta

Origin blog.csdn.net/michellechouu/article/details/50723091
Recomendado
Clasificación