![](/img/trans.png)
[英]C++ / Qt: How can I detect when a hostname or IP address refers to the current system?
[英]How can I change the variable to which a C++ reference refers?
如果我有這個:
int a = 2;
int b = 4;
int &ref = a;
如何在此代碼后使ref
引用b
?
這是不可能的,這是設計使然。 引用不能被反彈。
在 C++11 中有 new(ish) std::reference_wrapper 。
#include <functional>
int main() {
int a = 2;
int b = 4;
auto ref = std::ref(a);
//std::reference_wrapper<int> ref = std::ref(a); <- Or with the type specified
ref = std::ref(b);
}
這對於在容器中存儲引用也很有用。
你不能重新分配一個引用,但是如果你正在尋找可以提供類似能力的東西,你可以做一個指針。
int a = 2;
int b = 4;
int* ptr = &a; //ptr points to memory location of a.
ptr = &b; //ptr points to memory location of b now.
您可以使用以下命令獲取或設置指針內的值:
*ptr = 5; //set
int c = *ptr; //get
正式地說,這是不可能的,因為這是設計禁止的。 隨意地說,這是可能的。
引用存儲為指針,因此只要知道如何獲取其地址,就可以隨時更改它指向的位置。 同理,當你無權訪問時,你也可以改變const變量、const成員變量甚至私有成員變量的值。
例如,以下代碼更改了類 A 的 const 私有成員引用:
#include <iostream>
using namespace std;
class A{
private:
const int &i1;
public:
A(int &a):i1(a){}
int geti(){return i1;}
int *getip(){return (int*)&i1;}
};
int main(int argc, char *argv[]){
int i=5, j=10;
A a(i);
cout << "before change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
i=6; cout << "setting i to 6" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
*(int**)&a = &j; // the key step that changes A's member reference
cout << endl << "after change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
j=11; cout << "setting j to 11" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
return 0;
}
程序輸出:
before change:
&a.i1=0x7fff1b624140 &i=0x7fff1b624140 &j=0x7fff1b624150
i=5 j=10 a.i1=5
setting i to 6
i=6 j=10 a.i1=6
after change:
&a.i1=0x7fff1b624150 &i=0x7fff1b624140 &j=0x7fff1b624150
i=6 j=10 a.i1=10
setting j to 11
i=6 j=11 a.i1=11
如您所見, a.i1最初指向i ,更改后指向j 。
然而,這樣做被認為是危險的,因此不推薦,因為它違背了數據封裝和 OOP 的初衷。 這更像是內存地址黑客攻擊。
您不能重新分配參考。
這是不可能的。 C++ 只是不允許您重新綁定引用指向的內容。
但是,如果你想使用技巧,你幾乎可以用一個新的范圍來模擬它(永遠不要在真實的程序中這樣做):
int a = 2;
int b = 4;
int &ref = a;
{
int& ref = b; // Shadows the original ref so everything inside this { } refers to `ref` as `b` now.
}
您可以使用放置 new 輕松制作參考包裝器:
template< class T >
class RefWrapper
{
public:
RefWrapper( T& v ) : m_v( v ){}
operator T&(){ return m_v; }
T& operator=( const T& a ){ m_v = a; return m_v;}
//...... //
void remap( T& v )
{
//re-map reference
new (this) RefWrapper(v);
}
private:
T& m_v;
};
int32 a = 0;
int32 b = 0;
RefWrapper< int > r( a );
r = 1; // a = 1 now
r.remap( b );
r = 2; // b = 2 now
這個有可能。 因為在引擎蓋下,引用是一個指針。 以下代碼將打印“hello world”
#include "stdlib.h"
#include "stdio.h"
#include <string>
using namespace std;
class ReferenceChange
{
public:
size_t otherVariable;
string& ref;
ReferenceChange() : ref(*((string*)NULL)) {}
void setRef(string& str) {
*(&this->otherVariable + 1) = (size_t)&str;
}
};
void main()
{
string a("hello");
string b("world");
ReferenceChange rc;
rc.setRef(a);
printf("%s ", rc.ref.c_str());
rc.setRef(b);
printf("%s\n", rc.ref.c_str());
}
正如其他答案所述,這是不可能的。
但是,如果您將引用存儲在class
或struct
,則可以使用placement new 重新創建整個內容,因此引用被重新綁定。 正如@HolyBlackCat 所指出的,不要忘記使用std::launder
訪問重新創建的對象或使用從放置 new 返回的指針。 考慮我的例子:
#include <iostream>
struct A {
A(int& ref) : ref(ref) {}
// A reference stored as a field
int& ref;
};
int main() {
int a = 42;
int b = 43;
// When instance is created, the reference is bound to a
A ref_container(a);
std::cout <<
"&ref_container.ref = " << &ref_container.ref << std::endl <<
"&a = " << &a << std::endl << std::endl;
// Re-create the instance, and bind the reference to b
A* new_ref_container = new(&ref_container) A(b);
std::cout <<
// &ref_container and new_ref_container are the same pointers
"&ref_container = " << &ref_container << std::endl <<
"new_ref_container = " << new_ref_container << std::endl <<
"&new_ref_container.ref = " << &new_ref_container->ref << std::endl <<
"&b = " << &b << std::endl << std::endl;
return 0;
}
輸出是:
&ref_container.ref = 0x7ffdcb5f8c44
&a = 0x7ffdcb5f8c44
&ref_container = 0x7ffdcb5f8c38
new_ref_container = 0x7ffdcb5f8c38
&new_ref_container.ref = 0x7ffdcb5f8c40
&b = 0x7ffdcb5f8c40
雖然這是一個壞主意,因為它違背了使用引用的目的,但可以直接更改引用
const_cast< int& >(ref)=b;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.