简体   繁体   English

static_cast <const A>(* this)和static_cast <const A&>(* this)之间的区别

[英]difference between static_cast<const A>(*this) and static_cast<const A&>(*this)

in the following code ( taken from effective C++ ): 在以下代码中(取自有效的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;
}

In this code, if you change the static_cast from const TextBlock& to const TextBlock, this results in non-const version of operator[] getting called recursively. 在此代码中,如果将static_cast从const TextBlock更改为const TextBlock,则会导致以递归方式调用operator []的非const版本。 Can anyone explain what's the reason behind this ( why const TextBlock results in not calling const member function operator[] ). 任何人都可以解释这背后的原因是什么(为什么const TextBlock导致不调用const成员函数operator [])。

The reason is because 原因是因为

const A a();

and

A b();

are different objects, and in CPP non-constant objects cannot call constant functions and vice versa; 是不同的对象,并且在CPP非常量对象中不能调用常量函数,反之亦然; therefore, you need the same function to be declared twice for a const and non-const object respectively. 因此,您需要为const和非const对象分别声明两次相同的函数。

cout << a[0] << endl;

is legal, but 是合法的,但是

cout << b[0] << endl;

is not. 不是。 For that reason you should overload [] operator for non-const object. 因此,您应该为非const对象重载[]运算符。 In order to avoid copying the code, author suggest using a function for const object through casting away its constness. 为了避免复制代码,作者建议通过抛弃其constness来使用const对象的函数。 For that reason you get: 出于这个原因,你得到:

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

in other words, you just convert your object to const 换句话说,您只需将对象转换为const

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

try to use []operator of const obj 尝试使用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
}

get an error because []operator of const function returns const char& and this function returns char&. 得到一个错误,因为const函数的[]运算符返回const char&并且此函数返回char&。 Thus cast constness away 因此施放常数

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

Now you are done. 现在你完成了。 The question is: "How 问题是:“如何

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

became this: 成了这个:

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

? The reason for that is when you are using temp - you are making implicit cast of non-const to a const object, thus you can replace: 原因是当你使用temp时 - 你正在对const对象进行非const的隐式转换,因此你可以替换:

const A temp = *this;                                // implicit cast

with

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

this also works: 这也有效:

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

and since you can make an explicit cast - you don't need a temp anymore, thus: 因为你可以做一个明确的演员 - 你不再需要一个临时演员,因此:

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

this will return a non-const ref to a char from this const-casted object that calls an overloaded operator[] :) Exactly for that reason you cannot use 这将从这个const-casted对象返回一个非const引用,该对象调用一个重载的运算符[] :)正是因为这个原因你不能使用

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

because this is a not-const object; 因为这是一个非const对象; therefore, it will make it to call not cost function (to overload operator[]) which will cause an infinite recursion. 因此,它将调用非成本函数(重载operator []),这将导致无限递归。

Hope it makes sense. 希望它有意义。

Different operator[] function we called 我们调用了不同的operator []函数

When you define two object, one is const and another is non-const like this: const TextBlock a("Hello"); TextBlock b("World"); 定义两个对象时,一个是const,另一个是非const,如下所示: const TextBlock a("Hello"); TextBlock b("World"); const TextBlock a("Hello"); TextBlock b("World");

When you use a[0] and b[0] , different kind of operator[] will be called.The first one -- a[0] , will call the const function: 当你使用a[0]b[0] a[0] ,将调用不同类型的operator[]第一个 - a[0] ,将调用const函数:

const char &operator[](int) const;

Because a is a const object, each operation on it can't change its value. 因为a是一个const对象,所以它上面的每个操作都不能改变它的值。 So when it use the operator [] ,the const version will be called and return a const char& type, which also means we can't change its members' values. 因此,当它使用operator [] ,将调用const版本并返回一个const char& type,这也意味着我们无法更改其成员的值。

On the other hand, the second one -- b[0] will call the non-const function: 另一方面,第二个 - b[0]将调用非const函数:

char &operator[](int);

The object can be changed, also can its member. 对象可以更改,也可以更改其成员。 So this function returns a char & type, which can be modified. 所以这个函数返回一个char &类型,可以修改它。


What's being done in non-const function ? 在非const函数中做了什么?

So let's see the connection between non-const function and const function. 那么让我们看看非const函数和const函数之间的联系。 In your program, non-const function is realized by calling const function. 在你的程序中,通过调用const函数来实现非const函数。

Normally, a non-const object can not call the const function directly. 通常,非const对象不能直接调用const函数。 But we can change the attribute by static_cast<> . 但我们可以通过static_cast<>更改属性。 Thus we can transform object b into const TextBlock ,so that it can call the const function. 因此,我们可以将对象b转换为const TextBlock ,以便它可以调用const函数。

We do this in char &operator[](int index) ,which can reduce code reusing. 我们在char &operator[](int index)执行此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] ); }

When using static_cast<const TextBlock &>(*this) , it implicitly define a temporary object which is the TextBlock & to const TextBlock & conversion on *this . 当使用static_cast<const TextBlock &>(*this) ,它隐式定义一个临时对象,它是TextBlock & const TextBlock &转换为*this

After the conversion, we have a temporary object and we called it tmp . 转换后,我们有一个临时对象,我们称之为tmp So we can use tmp[0] to called the const function, which is what we exactly do. 所以我们可以使用tmp[0]来调用const函数,这正是我们所做的。

After returning from the const function, we get a value which type is const char & . 从const函数返回后,我们得到一个类型为const char & But we we actually want to is char & . 但我们实际上想要的是char & So we use const_cast<char &> remove the const attribute from the return value. 所以我们使用const_cast<char &>从返回值中删除const属性。 After this, we get a non-const reference in char, which values can be modified by us. 在此之后,我们在char中得到一个非const引用,我们可以修改这些值。

Actually, the return statement in non-const function can be replaced like this: 实际上,非const函数中的return语句可以像这样替换:

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

The tmp is the temporary reference to *this(Not a temporary object). tmp是* this(不是临时对象)的临时引用。 We have an implicitly conversion from TextBlock & to const TextBlock & here, whereas there is an explicitly conversion in the original return statement. 我们有一个隐式的从TextBlock &转换到const TextBlock & here,而在原始的return语句中有一个显式转换。

Remember to add the & in the first statement , which represents that we use a reference to object instead of an real object. 请记住在第一个语句中添加& ,它表示我们使用对象的引用而不是真实对象。 Or it will call an assignment constructer to generate a new object. 或者它将调用赋值构造函数来生成新对象。 If it happens, tmp will have nothing to do with *this . 如果它发生, tmp将与*this无关。 They are different object even if they have the same value. 即使它们具有相同的值,它们也是不同的对象。 Whatever we change tmp, the actual object we want to operate will not change! 无论我们改变tmp,我们想要操作的实际对象都不会改变!

The code below works - with the return values changed to char to avoid the issue reko_t found with returning a reference to an already-gone temporary - on g++ 3.4.6. 下面的代码工作 - 将返回值更改为char以避免在返回对已经消失的临时引用的引用时发现reko_t的问题 - 在g ++ 3.4.6上。

To explain the problem... 解释问题......

static_cast<const TextBlock>(*this)

...is effectively the same as... ......实际上和...一样

const TextBlock temporary = *this;

...which you then index into and return a reference. ...然后您将其编入索引并返回引用。 But, that temporary is gone from the stack by the time that reference is used. 但是,在使用引用时,临时值已从堆栈中消失。 Given you were returning such a reference, your behaviour was technically undefined. 鉴于您正在返回此类引用,您的行为在技术上是未定义的。

Does your compiler work with the code below? 你的编译器是否使用下面的代码? (type of position standardised at int to avoid ambiguity). (在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';
}

char& operator[](std::size_t position) and char& operator[](std::size_t position) const are different. char& operator[](std::size_t position)char& operator[](std::size_t position) const是不同的。 Note the 'const' after the function declaration. 注意函数声明后的'const'。 The first one is the 'non-const' version of the operator, while the second is the const version of the operator. 第一个是运算符的“非const”版本,第二个是运算符的const版本。 The non-const operator function gets called when the instance of that class is non-const and const version gets called when the object is 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

When you say (*this)[position] inside the non-const version of the operator, it calls the non-const version, which again calls the non-const version of the operator and it becomes an infinite loop. 当你在运算符的非const版本中说(* this)[position]时,它调用非const版本,它再次调用运算符的非const版本,它变成一个无限循环。 By doing that casting you're essentially calling the const version of the same operator. 通过执行该转换,您实际上是调用同一运算符的const版本。

EDIT: Hmm.. seems like the problem is not as it seems. 编辑:嗯..似乎问题不像它似乎。 Do you have a copy-constructor for that class? 你有那个类的拷贝构造函数吗? I'm guessing it's that which is causing this issue. 我猜这是造成这个问题的原因。

EDIT2: I think I've got it. EDIT2:我想我已经明白了。 a[i] -> creates temporary variable upon const cast without reference (const A) -> temp[position] -> creates temporary variable upon const cast without reference -> temp2[position] -> and it continues..... a [i] - >在const cast上创建临时变量而不引用(const A) - > temp [position] - >在const cast上创建临时变量而不引用 - > temp2 [position] - >并继续.....
while the one with const cast with reference (const A&) the temporary variable is not created, hence escaping the death-loop. 而一个与常量参考 (常量A&)投不创建临时变量,因此逸出死亡环。

To make it more clear... static_cast<const TextBlock>(*this)[position]; 为了使它更清楚...... static_cast<const TextBlock>(*this)[position]; Break-down of the above statement would be: 上述陈述的细分将是:

  • Convert *this to const TextBlock 将* this转换为const TextBlock
  • Create a temporary variable to hold the const TextBlock (copy-constructor called passing const TextBlock) 创建一个临时变量来保存const TextBlock(复制构造函数称为传递const TextBlock)
  • Call the operator[] on the temporary variable, which is NOT const because it was temporary. 在临时变量上调用operator [],这不是const,因为它是临时的。
  • Temporary variable goes through the above process. 临时变量经历上述过程。

Your operators have different inparameter types 您的运算符具有不同的参数类型

char& operator[](std::size_t position) char&operator [](std :: size_t position)
const char& operator[](int index) const <- Should also be std::size_t const char&operator [](int index)const < - 也应该是std :: size_t

This might be the solution you are looking for. 这可能是您正在寻找的解决方案。 Did the example from the book have different types for the inparameter? 本书的例子是否有不同类型的参数? Remember that type casting works on the return value. 请记住,类型转换适用于返回值。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM