C++中如何把一個變數的值作為另一個變數的名?

剛開始自學的c++,IDE為Qt,版本為5.4.2…別說我蠢…

————————————————————

8-11修改:

不知道我這樣理解的需求對不對,我最近也碰到了差不多的變態需求如下:

RELATION結構如下:

業務需求輸入A11後對RELATION關係進行遍歷,查出如下格式的表單:

查到的RELATION樹結構不一樣,輸出的表單列數還要相應變化,簡直有毒,完全不知道該怎麼做。

求大佬指點迷津。


這其實是一個好問題。Perl語言入門那本書里提到:當你問到這個問題的時候,說明你有了一些進步;而當你明白為什麼通常都不需要這個特性的時候,說明你又有了一些進步。

如果你想在運行時把一個變數的字元串內容當做另一個變數的名字,說明語言真的在運行時是通過字元串的名字來訪問變數的。而C、C++、Fortran、Rust之類的高性能語言都不這麼做,因為這相當於運行時進行查找,非常耗計算力。他們在編譯時就把變數轉換成了「固定」的地址調用,運行時並不存在變數名這個東西。

即使對於能夠這麼做的語言,也通常不鼓勵你這麼做。這是因為變數名是程序的一部分,這麼做相當於在用數據去修改程序,不但非常容易混亂,而且在大程序里這是潛在的安全性問題。

實際上你需要的是另一種東西:鍵值對的查找表,鍵是字元串,值是你需要的東西。在C++里,你可以簡單地用標準庫的std::map或者std::unordered_map。

==========

補充:允許你這麼做的語言,通常都:

  • 很古老;
  • 缺乏變數引用的能力,必須這麼做;
  • 自己放棄治療,不打算用來構建大型程序。

我知道的有shell腳本、CMake、Perl。這裡面,shell很古老;CMake是構建腳本,不是通用語言;Perl並不鼓勵你這麼做,use strict之後也不允許你這麼做。

================

繼續補充:

現在很多語言通過在解釋器里增加優化步驟、中間代碼編譯到native code一類的技術,可以極大地改善運行效率。

不過即使如此,你原本就需要付出的代價是不能被減少的。比如這個題目里提到的運行時符號查找,即使你用C++做,也依然不能免除一次字元串hash查找。

===================

對於題目增加內容的補充:

多層不定連接的問題,顯然需要使用圖來解決。首先自己定義好節點對象和邊對象,然後也許需要一些全局的單步關係映射表(比如簡單的誰的父是誰、誰的子是誰)。剩下的事情,基本就是一些圖論的演算法問題。

反正無論如何,你也不應當使用動態產生變數來搞這種事,實際上僅僅這樣也搞不定這種事。

如果你不需要在後台解決這個問題,可以接受交互程序,那你可以使用cytoscape。這個軟體可以從兩兩關係的列表生成網路,帶有一些分析和排版功能,常用於生物學代謝調控網路的可視化和分析。


對,那是不可能的


只能用map模擬你的動態對象

要變成語言上的變數是不可能的


C++?那是不可能的,除非你有預處理程序,就像 Qt 里的 moc。

既然題主用了 Qt,那可以嘗試深入研究一下 QObject 和 Qt 的 Meta-Object System,應該可以滿足你的需求。


既然用的Qt,你可知道

QObject obj;obj.setProperty("name", "hello world");

QJsonObject obj;obj["name"]="hello world"

QMap& map

.....

裡面的name都可以換成運行時變數的值。

個人比較傾向用QJson*,因為常用的數據結構都能用json來描述,配上QVariant簡直太好用了。


名字在編譯後就可以給扔掉了。

不過你可以修改符號表把別的名字改成你想要的,就當那個符號原來就叫你這名字就好了。曲線救國。


只能用map模擬


感覺反射就是有點像這個特性啊。

當然這裡有個先後的問題。反射是現有成員名稱再有變數值。

不過很多可以反射的語言都是可以動態載入的。

或者也可以這樣,用C#+scriptcs 之類的腳本語言相結合。? 至少語言語法層面就及其接近一種語言了?


PhP能,它是全世界最好的語言!誰敢反駁我我打爆他的dog頭!


並沒有這樣的支持,但是不代表做不到。

我的想法是,在c編譯器上套一層預處理,利用map來實現如下功能:

  1. 當你在某個作用域 A 定義變數時,

int a = 1;

預處理器的結果是

  • 如果 A 中第一次定義該類型變數

則先在全局作用域定義

std::map A&;

然後在對應為止把代碼替換為

A["a"] = 1;

  • 否則

    直接替換代碼為

A["a"] = 1;

那麼如果你的變數是以下string類型的,你的問題就能得到解決。需要你實現的功能如下

2. 對於代碼片段

${var}

替換為

A["var"]

這樣做的確是很簡單的事情,但是其實會出現很多問題,基本是不可能拿來通用的,要通用得像下面這樣。

1. 命名衝突

建議把管理作用域的有關變數A進行某種編碼。比如clang可以支持UTF8,那麼你可以把A的改成某個值大於255的Unicode碼。直接加一個固定常數就可以了。

但我們還是把這個變數說成A。

這樣一來還有一個好處,我們可以用這樣的變數名。

A_(a)_b
A_(a_b)

2. 如何讓預處理識別定義變數時的作用域?

你可以根據是否處於大括弧中。根據大括弧之前的標誌(類定義,函數定義,空),來決定作用域的名字以及從屬結構

3. 作用域要分類型。

畢竟 std :: map & 只能存放type一種類型的數據,所以之前說的,只用一個map來存一個作用域的所有變數顯然不可能。

我的建議是每個作用域需要至少定義(如果要做優化可以再定義一個map來用查看某類型是否在該作用域中定義)一個map來當類型表,類型呢是std::map&,變數名-&>類型鍵對。

那麼現在就是這樣: 對於某作用域A,變數類型表是A : std::map&< var_name: string, type_name: string&> , 當定義某個新變數a時,如果A的values里有a的類型type_a,那麼直接

A_type_a ["a"] = ...

否則在全局變數里定義一個

A_type_a = std::map&

後再定義變數a。

索引一個變數a時,首先看變數類型 A["a"],而且有 ${A["a"]} = type_a,然後索引

A_ ${A["a"]} ["a"]

即可。

4. 作用域的從屬結構

這也會導致問題。

對於 ${var}, 你要如何去尋找它的作用域?

比如說var的值是"val",我們有兩個作用域,一個是A,它是一個函數a的作用域,一個是B,是 函數a內部的一個子作用域,預處理代碼 ${var} 時,正位於在B里。

你的預處理程序只能判斷當前處於作用域B中,但是如果B沒有鍵"val",那你的程序又不能往上去找A作用域以及更頂層的全局作用域了。

所以你需要寫一個管理作用域的數據結構,就是一個樹狀圖,每個節點都是一個作用域,在尋找某個變數時,當前節點找不到,那麼回到上一代直系那裡繼續找,如果根節點也找不到,那麼就報錯,"Error: Variable not found"。

5. 如何處理類似下面這樣的定義方式。

int *a;
const int* a;
const *int a;

首先任意類型的指針要作為一種單獨類型,比如 *int是一種,放到

//前面說過,有關作用域的變數都編碼了,現在A_(*int)應該變成幾個unicode字元。
A_(*int) : std::map&

里去,對**int,放到

A_(**int) : std::map&里(命名衝突自己解決咯

但是const這個怎麼處理呢?這樣吧。

我們對於作用域A中存儲類型type_i的map,定義兩個,一個叫A_type_i,一個叫

A_type_i_immutable。

舉例子, 對變數a : const int,放到

A_int_immutable : std::map&

里,而類型表則是需要註冊一下,A["a"] = "const int"。

如果是 const type_i * var, 放到

A_*(type_i_immutable)

里, 類型註冊為 const type_i * 。

如果是 const * type_i var, 放到

A_(*type_i)_immutable

里, 類型註冊為 const * type_i 。

這裡也揭示了const 的本質。

嘛,以上就是我針對你這個問題的一個解法。

雖然還有一些問題沒解決,比如多文件關聯導致的衝突,都需要你手動搞定,但是如果你把上面那5點都解決了,相信剩下的不會非常困難。

至於預處理器,隨便拿個腳本語言跑就行了,比如Julia什麼的。


Javascript能,它是全世界最好的語言!誰敢反駁我我打爆他的dog頭!


基本上不可能,畢竟運行時不知道各個函數的入口在哪。不過可以定義函數指針搞這種騷操作。

C++不熟,下邊是C的方式

typedef void(*FuncType)(int);

FuncType A;
FuncType B;

enum {
FUNCA,
FUNCB,
};

FuncType funcArray[] = {
[FUNCA] = A,
[FUNCB] = B
};

...
int funcNumber = xxx;
funcArray[funcNumber];

顯而易見的看起來很蛋疼


嗯,這也許是一個典型:我根本就不是要把一個變數的值作為另一個變數的名,而只是想實現某個功能需求。

所以,不懂的情況下,應該問:我有一個這樣這樣的需求,應該怎麼做?而不是問:我這麼這麼做可以么?


std::map& vartable;


在程序裡面,用文件打開源文件,把所有的代碼讀入到字元串裡面,然後在字元串的main函數裡面加入一個用需要的字元串命名的變數的聲明。然後把修改好的源代碼寫入一個新的cpp文件(名字不一樣的),用system命令調用命令行g++編譯新的cpp文件。得到exe,搞定。


用 map 啊,用 map 啊,用 map 啊。

py 和 js 的變數其實也是存在類似 map 的東西里的。


這個需求為什麼要實現「一個變數值是另一個變數的名?」這種東西?

可以用個map對你輸入的東西進行查找,對應的pair的第二項可以裡面可以找到指向父項的指針,或者你可以弄個hash都可以(C++ 11以上叫unorderedmap),每一個項暴露遍歷的介面就可以了,做個迭代器啥的


把變數的值列印出來,然後寫到程序里,輕鬆實現


假如說是int變數的話嘛,可以建立一個map

map&a;

假如說第一個變數的值 cjy=」cjyyy」

那麼通過使用 a [cjy ]=2333相當於是對cjy的值對應的變數賦值啦

不知道題主是不是想實現這種功能

|_?)


變數值是動態運行時,變數名是靜態編譯期,C++是靜態編程語言,你說的一般是實現不了的,只能在運行時模擬,或者使用編譯期的匿名類對象(進入到了C++的魔法地帶了)。


推薦閱讀:

如果程序語言的賦值變為左值賦予右值會更好嗎?
想從事遊戲製作/設計行業,需要學哪些編程語言?
C 語言程序變數作用域的實現機制是什麼?
哪些字體適合程序員用來維護代碼?
達到什麼樣的程度才算精通 Android開發?

TAG:QtC開發框架 | 程序 | C |