程序员面试题精选100题(56)-C/C++/C#面试题(4)
問題(16):運(yùn)行如下的C++代碼,輸出是什么?
class A { public:virtual void Fun(int number = 10){std::cout << "A::Fun with number " << number;} };class B: public A { public:virtual void Fun(int number = 20){std::cout << "B::Fun with number " << number;} };int main() {B b;A &a = b;a.Fun(); }
答案:輸出B::Fun with number 10。由于a是一個(gè)指向B實(shí)例的引用,因此在運(yùn)行的時(shí)候會調(diào)用B::Fun。但缺省參數(shù)是在編譯期決定的。在編譯的時(shí)候,編譯器只知道a是一個(gè)類型a的引用,具體指向什么類型在編譯期是不能確定的,因此會按照A::Fun的聲明把缺省參數(shù)number設(shè)為10。
????????????這一題的關(guān)鍵在于理解確定缺省參數(shù)的值是在編譯的時(shí)候,但確定引用、指針的虛函數(shù)調(diào)用哪個(gè)類型的函數(shù)是在運(yùn)行的時(shí)候。
問題(17):運(yùn)行如下的C代碼,輸出是什么?
char* GetString1() {char p[] = "Hello World";return p; }char* GetString2() {char *p = "Hello World";return p; }int _tmain(int argc, _TCHAR* argv[]) {printf("GetString1 returns: %s. \n", GetString1());printf("GetString2 returns: %s. \n", GetString2());return 0; }
答案:輸出兩行,第一行GetString1 returns:?后面跟的是一串隨機(jī)的內(nèi)容,而第二行GetString2 returns: Hello World.?兩個(gè)函數(shù)的區(qū)別在于GetString1中是一個(gè)數(shù)組,而GetString2中是一個(gè)指針。
當(dāng)運(yùn)行到GetString1時(shí),p是一個(gè)數(shù)組,會開辟一塊內(nèi)存,并拷貝"Hello World"初始化該數(shù)組。接著返回?cái)?shù)組的首地址并退出該函數(shù)。由于p是GetString1內(nèi)的一個(gè)局部變量,當(dāng)運(yùn)行到這個(gè)函數(shù)外面的時(shí)候,這個(gè)數(shù)組的內(nèi)存會被釋放掉。因此在_tmain函數(shù)里再去訪問這個(gè)數(shù)組的內(nèi)容時(shí),結(jié)果是隨機(jī)的。
當(dāng)運(yùn)行到GetString2時(shí),p是一個(gè)指針,它指向的是字符串常量區(qū)的一個(gè)常量字符串。該常量字符串是一個(gè)全局的,并不會因?yàn)橥顺龊瘮?shù)GetString2而被釋放掉。因此在_tmain中仍然根據(jù)GetString2返回的地址得到字符串"Hello World"。
問題(18):運(yùn)行下圖中C#代碼,輸出的結(jié)果是什么?
namespace StaticVariableInAppDomain {[Serializable]internal class A : MarshalByRefObject{public static int Number;public void SetNumber(int value){Number = value;}}[Serializable]internal class B{public static int Number;public void SetNumber(int value){Number = value;}}class Program{static void Main(string[] args){String assamblyName = Assembly.GetEntryAssembly().FullName;AppDomain domain = AppDomain.CreateDomain("NewDomain");A.Number = 10;String nameOfA = typeof(A).FullName;A a = domain.CreateInstanceAndUnwrap(assamblyName, nameOfA) as A;a.SetNumber(20);Console.WriteLine("Number in class A is {0}", A.Number);B.Number = 10;String nameOfB = typeof(B).FullName;B b = domain.CreateInstanceAndUnwrap(assamblyName, nameOfB) as B;b.SetNumber(20);Console.WriteLine("Number in class B is {0}", B.Number);}} }
答案:輸出兩行,第一行是Number in class A is 10,而第二行是Number in class B is 20。上述C#代碼先創(chuàng)建一個(gè)命名為NewDomain的應(yīng)用程序域,并在該域中利用反射機(jī)制創(chuàng)建類型A的一個(gè)實(shí)例和類型B的一個(gè)實(shí)例。我們注意到類型A是繼承自MarshalByRefObject,而B不是。雖然這兩個(gè)類型的結(jié)構(gòu)一樣,但由于基類不同而導(dǎo)致在跨越應(yīng)用程序域的邊界時(shí)表現(xiàn)出的行為將大不相同。
??????由于A繼承MarshalByRefObject,那么a實(shí)際上只是在缺省的域中的一個(gè)代理,它指向位于NewDomain域中的A的一個(gè)實(shí)例。當(dāng)a.SetNumber時(shí),是在NewDomain域中調(diào)用該方法,它將修改NewDomain域中靜態(tài)變量A.Number的值并設(shè)為20。由于靜態(tài)變量在每個(gè)應(yīng)用程序域中都有一份獨(dú)立的拷貝,修改NewDomain域中的靜態(tài)變量A.Number對缺省域中的靜態(tài)變量A.NewDomain沒有任何影響。由于Console.WriteLine是在缺省的應(yīng)用程序域中輸出A.Number,因此輸出仍然是10。
????B只從Object繼承而來的類型,它的實(shí)例穿越應(yīng)用程序域的邊界時(shí),將會完整地拷貝實(shí)例。在上述代碼中,我們盡管試圖在NewDomani域中生成B的實(shí)例,但會把實(shí)例b拷貝到缺省的域。此時(shí),調(diào)用b.SetNumber也是在缺省的域上進(jìn)行,它將修改缺省的域上的A.Number并設(shè)為20。因此這一次輸出的是20。
問題(19):運(yùn)行下圖中C代碼,輸出的結(jié)果是什么?
int _tmain(int argc, _TCHAR* argv[]) {char str1[] = "hello world";char str2[] = "hello world";char* str3 = "hello world";char* str4 = "hello world";if(str1 == str2)printf("str1 and str2 are same.\n");elseprintf("str1 and str2 are not same.\n");if(str3 == str4)printf("str3 and str4 are same.\n");elseprintf("str3 and str4 are not same.\n");return 0; }
答案:輸出兩行。第一行是str1 and str2 are not same,第二行是str3 and str4 are same。
str1和str2是兩個(gè)字符串?dāng)?shù)組。我們會為它們分配兩個(gè)長度為12個(gè)字節(jié)的空間,并把"hello world"的內(nèi)容分別拷貝到數(shù)組中去。這是兩個(gè)初始地址不同的數(shù)組,因此比較str1和str2的值,會不相同。str3和str4是兩個(gè)指針,我們無需為它們分配內(nèi)存以存儲字符串的內(nèi)容,而只需要把它們指向"hello world“在內(nèi)存中的地址就可以了。由于"hello world”是常量字符串,它在內(nèi)存中只有一個(gè)拷貝,因此str3和str4指向的是同一個(gè)地址。因此比較str3和str4的值,會是相同的。
問題(20):運(yùn)行下圖中C#代碼,輸出的結(jié)果是什么?并請比較這兩個(gè)類型各有什么特點(diǎn),有哪些區(qū)別。
namespace Singleton {public sealed class Singleton1{private Singleton1(){Console.WriteLine("Singleton1 constructed");}public static void Print(){Console.WriteLine("Singleton1 Print");}private static Singleton1 instance = new Singleton1();public static Singleton1 Instance{get{return instance;}}}public sealed class Singleton2{Singleton2(){Console.WriteLine("Singleton2 constructed");}public static void Print(){Console.WriteLine("Singleton2 Print");}public static Singleton2 Instance{get{return Nested.instance;}}class Nested{static Nested() { }internal static readonly Singleton2 instance = new Singleton2();}}class Program{static void Main(string[] args){Singleton1.Print();Singleton2.Print();}} }
答案:?輸出三行:第一行“Singleton1 constructed”,第二行“Singleton1 Print”,第三行“Singleton2 Print”。
當(dāng)我們調(diào)用Singleton1.Print時(shí),.NET運(yùn)行時(shí)會自動調(diào)用Singleton1的靜態(tài)構(gòu)造函數(shù),并初始化它的靜態(tài)變量。此時(shí)會創(chuàng)建一個(gè)Singleton1的實(shí)例,因此會調(diào)用它的構(gòu)造函數(shù)。Singleton2的實(shí)例是在Nested的靜態(tài)構(gòu)造函數(shù)里初始化的。只有當(dāng)類型Nested被使用時(shí),才回觸發(fā).NET運(yùn)行時(shí)調(diào)用它的靜態(tài)構(gòu)造函數(shù)。我們注意到我們只在Sington2.Instance里面用到了Nested。而在我們的代碼中,只調(diào)用了Singleton2.Print。因此不會創(chuàng)建Singleton2的實(shí)例,也不會調(diào)用它的構(gòu)造函數(shù)。
這兩個(gè)類型其實(shí)都是單例模式(Singleton)的實(shí)現(xiàn)。第二個(gè)實(shí)現(xiàn)Singleton2只在真的需要時(shí),才會創(chuàng)建實(shí)例,而第一個(gè)實(shí)現(xiàn)Singleton1則不然。第二個(gè)實(shí)現(xiàn)在空間效率上更好。
?
博主何海濤對本博客文章享有著作權(quán)。網(wǎng)絡(luò)轉(zhuǎn)載請注明出處http://zhedahht.blog.163.com/。整理出版物請和作者聯(lián)系。
總結(jié)
以上是生活随笔為你收集整理的程序员面试题精选100题(56)-C/C++/C#面试题(4)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员面试题精选100题(55)-不用+
- 下一篇: 程序员面试题精选100题(62)-C/C