static_cast <const a =“”>(* this)和static_cast <const a&=“”>(* this)</const> </const>之间的区别

时间:2010-09-27 09:34:31

标签: c++ pointers static this casting

在以下代码中(取自有效的C ++):

class A 
{
  ....
  char& operator[](std::size_t position)         // now just calls const op[]
  {
    return
      const_cast<char&>(           // cast away const on op[]'s return type;
        static_cast<const TextBlock&>(*this)   // add const to *this's type;
          [position]                           // call const version of op[]
      );
  }

  const char& operator[](int index) const
  {
     ...
  }
}
//complete example, tested with VC 2010
#include<iostream>
#include<string>

class TextBlock
{
public:
    TextBlock(std::string st):text(st){};
    TextBlock(char* cstr): text(cstr){};
    TextBlock(const TextBlock& r)
    {
        std::cout<<"copy constructor called"<<std::endl;
    }
    char& operator[](int index)
    {
        std::cout<<"non-const operator"<<std::endl;
        return const_cast<char&>(static_cast<const TextBlock>(*this)[index]);
    }

    const char& operator[](int index) const
    {
        std::cout<<"const operator"<<std::endl;
        return text[index];
    }

private:
    std::string text;
};

int main()
{
    TextBlock rt("hello");
    std::cout<<rt[0]<<std::endl;
}

在此代码中,如果从const TextBlock&amp;更改static_cast;对于const TextBlock,这会导致operator []的非const版本被递归调用。任何人都可以解释这背后的原因(为什么const TextBlock导致不调用const成员函数operator [])。

5 个答案:

答案 0 :(得分:3)

原因是因为

const A a();

A b();

是不同的对象,而在CPP非常量对象中不能调用常量函数,反之亦然;因此,您需要为const和非const对象分别声明两次相同的函数。

cout << a[0] << endl;

是合法的,但

cout << b[0] << endl;

不是。 因此,您应该为非const对象重载[]运算符。为了避免复制代码,作者建议通过抛弃其constness来使用const对象的函数。因此,你得到:

char& operator[](std::size_t position)
{
     return const_cast <char &>( static_cast <const A &>(*this) [position] );
}

换句话说,您只需将对象转换为const

char& operator[](std::size_t position)
{
     const A temp = *this;      //create a const object 
                                    //and assign current object to it
     ....
}

尝试使用const obj

的[]运算符
char& operator[](std::size_t position)
{
     const A temp = *this;      //create a const object 
                                    //and assign current object to it
     return temp[position];     // call an overloaded operator [] 
                                // of the const function
}

得到一个错误,因为const函数的[]运算符返回const char&amp;并且此函数返回char&amp ;.因此,施放常数

char& operator[](std::size_t position)
{
     const A temp = *this;      //create a const object 
                                //and assign current object to it
     return const_cast <char &>( temp[position] );
 }

现在你完成了。问题是:&#34;如何

const A temp = *this;
return const_cast <char &> (temp[position]);

成了这个:

return const_cast <char &> ( static_cast <const A &> (*this)[position]);

?原因是当你使用temp时 - 你正在对const对象进行非const的隐式转换,因此你可以替换:

const A temp = *this;                                // implicit cast

const A temp = static_cast <const A &> (*this)        //explicit  

这也有效:

const A temp = const_cast <const A &> (*this) 

因为你可以做一个明确的演员 - 你不再需要一个临时演员,因此:

return const_cast <char &> (static_cast <const A &>(*this)[position]);

这将从这个const-casted对象返回一个非const引用,该对象调用一个重载的operator [] :)正是因为这个原因你不能使用

return const_cast <char &> ((*this)[position]);

因为这是一个非const对象;因此,它将调用非成本函数(重载operator []),这将导致无限递归。

希望它有意义。

答案 1 :(得分:2)

我们调用

的不同operator []函数

定义两个对象时,一个是const,另一个是非const,如下所示: const TextBlock a("Hello"); TextBlock b("World");

当您使用a[0]b[0]时,将调用不同类型的operator[]。第一个 - a[0]将调用 const 功能:

const char &operator[](int) const;

因为a是一个const对象,所以它上面的每个操作都不能改变它的值。因此,当它使用运算符[]时,将调用const版本并返回const char&类型,这也意味着我们无法更改其成员的值。

另一方面,第二个 - b[0]将调用非const 函数:

char &operator[](int);

对象可以更改,也可以更改其成员。所以这个函数返回一个char &类型,可以修改。

在非const函数中做了什么?

让我们看看非const函数和const函数之间的联系。在你的程序中,通过调用const函数来实现非const函数。

通常,非const对象不能直接调用const函数。但我们可以通过static_cast<>更改属性。因此,我们可以将对象b转换为const TextBlock,以便它可以调用const函数。

我们这样做 char &operator[](int index) ,这可以减少代码重用。

char & operator[](int position) { // const TextBlock tmp = *this; // return const_cast<char &>(tmp[position]); return const_cast<char &>( (static_cast<const TextBlock &>(*this))[position] ); }

使用static_cast<const TextBlock &>(*this)时,它会隐式定义一个临时对象,即TextBlock &上的const TextBlock &*this转换。

转换后,我们有一个临时对象,我们称之为 tmp 。所以我们可以使用tmp[0]来调用const函数,这正是我们所做的。

从const函数返回后,我们得到一个类型为const char &的值。但我们实际上想要的是char &。所以我们使用const_cast<char &>从返回值中删除const属性。在此之后,我们在char中得到一个非const引用,我们可以修改这些值。

实际上,非const函数中的return语句可以像这样替换:

const TextBlcok &tmp = *this; return const_cast<char &>tmp[position];

tmp是* this(不是临时对象)的临时引用。我们在这里隐式转换从TextBlock &const TextBlock &,而在原始的return语句中有明确的转换。

请记住在第一个语句中添加& ,这表示我们使用对象的引用而不是真实对象。或者它将调用赋值构造函数来生成新对象。如果发生这种情况,tmp将与*this无关。即使它们具有相同的值,它们也是不同的对象。无论我们改变tmp,我们想要操作的实际对象都不会改变!

答案 2 :(得分:1)

以下代码有效 - 将返回值更改为char以避免在返回对已经消失的临时引用的引用时发现reko_t的问题 - 在g ++ 3.4.6上。

解释问题......

static_cast<const TextBlock>(*this)

...实际上与......相同。

const TextBlock temporary = *this;

...然后您将其编入索引并返回引用。但是,在使用引用时,临时值已从堆栈中消失。鉴于您正在返回此类引用,您的行为在技术上尚未定义。

您的编译器是否使用下面的代码? (在int标准化的职位类型,以避免含糊不清)。

#include <iostream>

struct A  
{ 

  char operator[](int position)         // now just calls const op[] 
  { 
    return 
        static_cast<const A>(*this)     // add const to *this's type; 
          [position];                   // call const version of op[] 
  } 

  const char operator[](int index) const 
  { 
    return x_[index];
  } 

  char x_[10];
};

int main()
{
  A a;
  strcpy(a.x_, "hello!");
  const A& ca = a;
  std::cout << a[0] << ca[1] << a[2] << ca[3] << a[4] << ca[5] << '\n';
}

答案 3 :(得分:0)

char& operator[](std::size_t position)char& operator[](std::size_t position) const不同。注意函数声明后的'const'。第一个是运算符的“非const”版本,第二个是运算符的const版本。当该类的实例为非const时调用非const运算符函数,当对象为const时调用const版本。

const A a;
char c = a[i]; // Calls the const version
A b;
char d = b[i]; // Calls the non-const version

当你在运算符的非const版本中说(* this)[position]时,它调用非const版本,它再次调用运算符的非const版本,它变成一个无限循环。通过执行该转换,您实际上是调用同一运算符的const版本。

编辑:嗯..似乎问题不像看起来那样。你有那个类的拷贝构造函数吗?我猜这是造成这个问题的原因。

编辑2:我想我已经知道了。 a [i] - &gt;在没有引用的情况下进行const转换时创建临时变量(const A) - &gt; temp [position] - &gt;在没有引用的情况下在const转换时创建临时变量 - &gt; temp2 [位置] - &gt;它继续.....
而使用const 引用(const A&amp;)的那个临时变量不会被创建,因此逃离死循环。

为了更清楚...... static_cast<const TextBlock>(*this)[position]; 上述陈述的细分将是:

  • 将*转换为const TextBlock
  • 创建一个临时变量来保存const TextBlock(复制构造函数称为传递const TextBlock)
  • 对临时变量调用operator [],这不是const,因为它是临时变量。
  • 临时变量经过上述过程。

答案 4 :(得分:0)

您的运营商有不同的参数类型

炭&安培; operator [](std :: size_t position)
const char&amp; operator [](int index)const&lt; - 也应该是std :: size_t

这可能是您正在寻找的解决方案。 本书的例子是否有不同类型的参数? 请记住,类型转换适用于返回值。

char& operator[](std::size_t index)
{
  std::cout<<"non-const operator"<<std::endl;
  const TextBlock &  ref = *this;
  return const_cast<char&>(ref[index]);
}