天天看點

另類加法,允許增加子函數

問答題

問答題1:下列代碼輸出啥?

#include <iostream>
using namespace std;
void func(char **m) {
	++m;
	cout << *m << endl;
}
int main() {
	static char *a[] = { "morning", "afternoon", "evening" };
	char **p;
	p = a;
	func(p);
	return 0;
}
           

提示:傳入到函數 func 中的是一個二級指針,進行++操作指向了 a[1] 這個位址,解引用得到 a[1] 值

這道題在C(弱類型)編譯環境可以通過,但是C++(強類型)編譯器不通過,因為 main 函數第一行左邊類型是const char* ,但是右邊是可變的指針數組,類型不比對

修改為

const char* a[] = { "morning", "afternoon", "evening" };
	char **p;
	p = (char**)a;
           

必須先讓等式兩邊類型相同,是以最後加個強制類型轉化;

答案:afternoon

問答題2:有如下程式?

class MyClass {
public:
	MyClass(int i = 0) {
		cout << 1; 
	}
	MyClass(const MyClass&x) {
		cout << 2; 
	}
	MyClass& operator=(const MyClass&x) {
		cout << 3;
		return*this; 
	}
	~MyClass() {
		cout << 4; 
	}
};
int main() {
	MyClass obj1(1), obj2(2), obj3(obj1);

	system("pause");
	return 0;
}
           

提示:調用兩次構造函數,一次拷貝拷貝構造函數,三次析構函數.

答案:112 444

問答題3:代碼執行後,a和b的值分别為?

class Test {
public:
	int a;
	int b;
	virtual void fun() {}
	Test(int temp1 = 0, int temp2 = 0){
		a = temp1;
		b = temp2;
	}
	int getA(){
		return a;
	}
	int getB(){
		return b;
	}
};

int main(){
	Test obj(5, 10);
	int* pInt = (int*)&obj;
	*(pInt + 0) = 100;
	*(pInt + 1) = 200;
	cout << "a = " << obj.getA() << endl;
	cout << "b = " << obj.getB() << endl;

	system("pause");
	return 0;
}
           

提示:對象 obj 中的a 和 b 分别為 5 和 10,但是由于沒有重載運算符,是以強制轉換為整型運算,不過這不是關鍵,關鍵是fun函數,由于指向虛函數表的指針占4個位元組(32), 其位址分布在整個類成員變量的位址的首部,接下來才是變量a的位址、b的位址,是以 +0 表示的位址是虛表指針,+1 是a的位址,也就是說 b 并沒有被重新指派.

答案:a = 200,b=10

問答題4:32位系統中,定義**a[3][4],則變量占用記憶體空間為?

指針在32位系統,占 4個位元組,指針數組中一共有 12 個指針,是以占48位元組.

問答題5:執行下面語句後的輸出為?

int I=1;
if(I<=0){
	printf("****\n") ;
}
else{
	printf("%%%%\n");
}
           

提示:%%% 表示 輸出兩個百分号

答案:%%

問答題6:類模闆的使用實際上是先将類模闆執行個體化為模闆類,再執行個體化成一個具體的類

問答題7:下列代碼輸出啥?

struct A {
	void foo() {
		printf("foo"); 
	}
	virtual void bar() {
		printf("bar"); 
	}
	A() {
		bar();
	}
};
struct B :A {
	void foo() {
		printf("b_foo"); 
	}
	void bar() {
		printf("b_bar"); 
	}
};

int main() {
	A *p = new B;
	p->foo();// B 中的 foo不是虛函數,是以會調用基類foo
	p->bar();// 實作了多态,B 中含有 bar 的虛函數,調用派生類中的函數.
	return 0;
}
           

提示:

A *p=newB;

/A 類指針指向一個執行個體化對象B, B類繼承A類,先調用父類的無參構造函數,bar()輸出

bar

,B類沒有自己顯示定義的構造函數,

p->foo();

執行B類裡的foo()函數,因為foo不是虛函數,是以直接調用父類的foo函數,輸出

foo

p->bar();

執行B類的bar()函數, 該函數為虛函數,調用子類的實作,輸出

b_bar

問答題8:下面的程式輸出可能是什麼?

class Printer {
public:
	Printer(std::string name) {
		std::cout << name; 
	}
};

class Container {
public:
	Container() 
		: b("b")
		, a("a")
	{}
	Printer a;
	Printer b;
};
int main() {
	Container c;
	return 0;
}
           

提示:初始化根據類成員定義的順序,與初始化清單中的書寫的順序沒有關系,是以先初始化a,然後才是b

答案:

"ab"

問答題9:代碼可以通過編譯嗎?如果不能應該如何修改?

template<class T>
class Foo {
	T tVar;
public:
	Foo(T t) : tVar(t) { }
};

template<class T>
class FooDerived : public Foo<T> {
// 加入構造函數
};

int main(){
	FooDerived<int> d(5);
	return 0;
}
           

提示:當基類構造函數需要外部傳遞參數才能進行初始化時,派生類必須顯式定義構造函數,為基類傳遞參數;基類如果不需要傳遞或者可以不傳遞參數,派生類可以不用顯式定義構造函數。

答案:添加後如下圖.

template<class T>
class FooDerived : public Foo<T> {
public:
	FooDerived(T val) 
		:Foo<T>(val)
	{}
};
           

程式設計題

程式設計題1:另類加法

請編寫一個函數,将兩個數字相加。不得使用

+

或其他算數運算符,給定兩個int A和B,請傳回

A+B

的值

測試樣例:1,2;傳回:3

提示:利用二進制模拟加法運算.

int addAB(int A, int B) {
	int sum = 0, carry = 0;
	while (B != 0) {
		//對應位的和
		sum = A ^ B;
		//對應位和的進位,既然是進位,就要整體左移一位
		carry = (A&B) << 1;
		A = sum;
		B = carry;
	}
	return sum;
}
           

簡化代碼

int addAB(int A, int B) {
	while (A & B << 1) {
		//對應位的和
		//對應位和的進位,既然是進位,就要整體左移一位
		A = A ^ B;
	}
	return A;
}
           

遞歸寫法

int addAB(int A, int B) {
	if(B==0){
    	return A;
	}
	return addAB(A^B,(A&B)<<1);
}
           

程式設計題2:求路徑總數

請編寫一個函數計算

n x m

的棋盤格子,沿着各自邊緣線從左上角走到右下角,總共有多少種走法,要求不能走回頭路,即:隻能往右和往下走,不能往左和往上走

示例1:輸入:2 2;輸出:6

方法一:遞歸計算路線,隻要 m 或 n 有一個等于1,則路線是 1+m 或者 1+ n ,如果有一個 等于 0,則傳回0

int pathNum(int n, int m){
	if (n > 1 && m > 1){
		return pathNum(n - 1, m) + pathNum(n, m - 1);
	}else if (((n >= 1) && (m == 1)) 
		|| ((n == 1) && (m >= 1))){
	
		return n + m;
	}
	else{
		return 0;
	}
}
           

方法二:動态規劃

提示:初始化一個二維數組,多增加一行和一列,第一行和第一列為1,其餘位置都是0

周遊到目前位置時,

dp[i][j]

表示到達 (i,j)位置的個數

轉義方程為

dp[i][j] = dp[i-1][j] + dp[i][j-1];

最後傳回

dp[n][m]

位置的數字即是最終答案.

#include <iostream>
#include <vector>
using namespace std;

int main(){
    int n,m;
    while(cin>>n>>m){
        vector<vector<int>>dp(n+1,vector<int>(m+1,0));
        for(int i=0;i<n+1;++i){
            for(int j=0;j<m+1;++j){
                if(i==0 || j==0){
                    dp[i][j] = 1;
                }else{
                    dp[i][j] = dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        cout<<dp[n][m]<<endl;
    }
    return 0;
}
           

繼續閱讀