Как работает ключевое слово "const"? - PullRequest
0 голосов
/ 25 февраля 2012
namespace pairDemo{

template<typename L, typename R>
class pair{
public:

    pair(const L& left,const R& right)
        :lft(left),rht(right)
    {
    }

    pair(const pair<L,R>& p)
        :lft(p.lft),rht(p.rht)
    {
    }

    L left() const{
        return lft;
    }
    R right() const{
        return rht;
    }

    void left(const L& left){
        lft = left;
    }
    void right(const R& right){
        rht = right;
    }
private:
    L lft;
    R rht;
};
}

// --------------------------------------------- ------

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

pairDemo::pair<int, double> func(int x, double y){
    pairDemo::pair<int, double> temp(x*2, x+y);
    return temp;
}

int main(){
    int x = 2; double y = 3.55;
    pairDemo::pair<int, double> myPair = func(x,y);
    cout << myPair.left() << myPair.right();
}

У меня вопрос к аргументу конструктора. Если я не объявлю "const", функция func () будет иметь ошибку. Я не знаю почему, и любой может мне помочь.

Ответы [ 4 ]

2 голосов
/ 25 февраля 2012

Поскольку вы передаете x * 2 и x + y в конструктор, ссылки должны быть объявлены как const (т. Е. Только для чтения).

Если вы передаете неконстант (т. Е. Read-write), тогда код функции сможет изменить ссылку, чтобы изменить значение того, что было передано. Это имеет смысл, если вы передаете x, y, потому что код может обновлять эти значения.

Но в этом случае изменение значения x * 2 или x + y не имеет смысла, компилятор настаивает на том, чтобы ссылка была постоянной.

1 голос
/ 25 февраля 2012

Если вы удалите const s из конструктора pair::pair(const L& left,const R& right), тогда код pairDemo::pair<int, double> temp(x*2, x+y); не будет работать, поскольку результат x*2 запрещает привязку к L& left, а x+y запрещает привязку до R& right.

C ++ имеет это правило, потому что разработчики считали, что параметры функции неконстантных ссылочных типов должны указывать, что функция может изменить значение и что это изменение должно быть видимым для вызывающей стороны.

рассмотреть следующие вопросы:

void foo(int &i) {
    i = 3;
}

foo(x); // sets x to 3
foo(1); // sets 1 to 3??? prohibited

Это может вызвать путаницу, если кто-то случайно вызовет foo с временным, например 1 или или x+y, или x*2, поэтому C ++ решает сделать безопасную вещь и не разрешить их компилировать.

C ++ 11 добавляет «ссылки на значения», которые имеют некоторые другие правила.

void bar(int &&i) { // && means 'rvalue reference' 
    i = 3;
}

bar(1); // sets 1 to 3!
bar(x); // prohibited.

Ссылки на rvalue должны означать, что функция получает временное значение, и что бы она ни делала с ней, она не повлияет на внешний мир. Теперь опасность состоит в том, что функция, принимающая ссылку на rvalue, будет случайно вызвана с помощью временного метода. Поэтому правила пытаются запретить вам передавать невременные значения, такие как x.

1 голос
/ 25 февраля 2012

Да, если у вас есть параметр типа int &, вы не можете передать аргумент x * 2.Наличие неконстантного ссылочного параметра позволяет изменять аргумент, и если вы решите игнорировать эти изменения (если они есть), вам нужно сделать это явно.

Что касается передачи x * 2 в const int &,может быть немного странно, что это работает, но на самом деле происходит то, что создается новая временная переменная, которой присваиваются x * 2, а эта переменная - это то, что передается функции.В этом случае нет проблемы с автоматическим созданием временного, потому что его значение все равно не изменится (вот почему у вас есть const, не так ли?).

1 голос
/ 25 февраля 2012
pair(const L& left,const R& right)
        : lft(left), rht(right)
{
}

pairDemo::pair<int, double> func(int x, double y) 
{
    pairDemo::pair<int, double> temp(x*2, x+y);
    return temp;                //   ^^^  ^^^
}                               //  temporaries here

Ваш конструктор берет свои параметры по ссылке. В func вы передаете временные объекты этому конструктору. Временные объекты могут связываться только с const ссылками, поэтому вы получаете сообщение об ошибке, если удаляете const. Если вы решили передать параметры по значению, вы можете опустить квалификаторы const.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...