好了,現在我要給大家講講面向對象的一些知識。上次說到了,面向對象是一種對現實世界理解和抽象的方法,是計算機編程技術發展到一定階段后的產物。一般地,面向對象具有繼承性、封裝性、多態性三個特征。 舉個簡單的例子吧,現在我讓你去用計算器計算3*4的結果,你會這么做呢?仔細想想,流程應該如下。 (1)買一個計算器; (2)輸入3*4; (3)按下=鍵,獲得結果。 這正好對應這三行代碼: (1)Calculator c; (2)c.inputFormula(“3*4”); (3)c.getResult(); 所以說,面向對象與現實非常貼合,這就是面向對象受歡迎的原因之一。 有人又會疑惑了,我怎么知道計算器對象具有哪些函數呢,函數的參數掃是什么,返回值又是什么?有沒有一個標準或者是文檔呢? 很負責的告訴你,有的。計算器有說明書,面向對象就有API。API:application Programming Interface,應用程序編程接口。 例如,這里的計算器類的API如下所示: 根據這個API,我們可以隨心所欲地使用計算器啦~ 然后有人又有疑惑了,你的API中為什么setFormula()函數要重載呢?為什么接收C++的字符串之外還要寫一個接收C風格的字符串呢? 這其實就是面向對象的多態性。通俗一點說,就是多種選擇隨我選。一個面向對象的優質代碼,往往就是盡可能多給與對方(使用者)更多的選擇。 此外我再通俗地說一下封裝性:即內部存儲和實現不關我的事。例如在計算器類中,getResult()函數是如何工作的,這個或許是字符串解析吧,或許是利用棧結構,或許是遞歸……反正我是不知道,也沒有必要知道,我只要會用就行了。就好像我們買電視,沒有人說一定要知道電視的結構、組成才能看電視吧。面向對象也是一樣的原理。 最后則是面向對象的繼承性。例如: (派生)人→學生→研究生 (繼承)研究生→學生→人 就是典型的一個繼承。 我們寫三個類(人、學生、研究生)的“戀愛”方法吧。
class Person
{int age;
void love(){cout<<
"fall in love at will" <<endl;}}
class Student:
public Person
{
int age;
void love(){
cout <<
"fall in love seriously" <<endl;}}
class Postgraduate:
public Student
{
int age;
void love(){
cout <<
"fall in love maturely" <<endl;}}
總而言之,這三類人是“隨心所欲的戀愛”,“認真的戀愛”,“成熟的戀愛”。如果這個時候定義一個研究生對象gth,調用“戀愛”方法后,輸出的肯定是“成熟的戀愛”。
Postgraduate gth;
gth.love();
這個就稱為方法(函數)覆蓋(重寫)。當然這里的覆蓋并不是指一定訪問不到了,只是使用起來好像是訪問不到了。如果想要完全覆蓋,需要使用虛函數。這里就不再贅述。 下面的概念很有趣。對于自然界很多物體(具體的或抽象的),一般都可以建立對象(實例化)。但是,對于一部分概念,其一般為一類統稱,一般不希望其實例化,例如水果、動物、蔬菜……例如,“xxx,給我拿一個水果來。”這句話其實就是有問題的。 但是,“水果”作為一個概念,的確擁有一些屬性(例如VC含量,重量)和方法(吃、存儲)等。所以我們希望定義一個類,其指定了一部分屬性和方法(方法空實現),該類不可實例化,只能通過繼承后再實例,達到自然界的高度仿真。 我們需要純虛函數來實現這個規律。 我們先寫水果類:
class Fruit
{
private :
double vcContent;
double weight;
public :
virtual void eat ()=
0 ;
virtual void store()=
0 ;
};
再寫蘋果類:
class Apple:
public Fruit
{
public :
void eat (){cout<<
"just eat it :)" <<endl;}
void store(){cout<<
"stored in shadow" <<endl;}
};
最后是main()函數
void main()
{
Apple apple;apple.eat();apple.store();
}
最后,我們來一個生動的實戰例子,來說明面向對象是如何編程的。
NOJ實戰 1058 Tom和Jerry在10*10的方格中: …….. ……*… …….. ………. …*.C…. …..… …*…… ..M……* ….…. ..…… C=Tom(貓) M=Jerry(老鼠) *=障礙物 .=空地 他們各自每秒中走一格,如果在某一秒末他們在同一格中,我們稱他們“相遇”。注意,“對穿”是不算相遇的。 他們移動方式相同:平時沿直線走,下一步如果會走到障礙物上去或者出界,就用1秒的時間做一個右轉90度。一開始他們都面向北方。 編程計算多少秒以后他們相遇。 我們簡要的對這個現實世界的產物進行抽象和建模: 然后我們回想,為什么位置和方向都是向量呢?看下面一張圖就能明了。 接下來,我們就可以進行代碼的編寫工作啦~
#include<iostream>
#define LENGTH 10
using namespace std;
class Vector
{
private :
int x,y;
public :
Vector (){x=y=
0 ;}
void setX(
int x){
this ->x=x;}
void setY(
int y){
this ->y=y;}
int getX(){
return x;}
int getY(){
return y;}
void setUp(){setX(-
1 );setY(
0 );}
void setDown(){setX(
1 );setY(
0 );}
void setLeft(){setX(
0 );setY(-
1 );}
void setRight(){setX(
0 );setY(
1 );}
bool operator ==(Vector v){
return getX()==v.getX() && getY()==v.getY();}
void output(){cout<<
"(" <<getX()<<
"," <<getY()<<
")" <<endl;}
};class Cat
{
private :Vector position;Vector direction;
public :
Cat (){position.setX(
0 );position.setY(
0 );direction.setUp();}
void setPosition(Vector position){
this ->position=position;}Vector getDirection(){
return direction;}Vector getPosition(){
return position;}
void turnRight(){
if (direction.getX()==-
1 && direction.getY()==
0 ) direction.setRight();
else if (direction.getX()==
1 && direction.getY()==
0 ) direction.setLeft();
else if (direction.getX()==
0 && direction.getY()==-
1 ) direction.setUp();
else if (direction.getX()==
0 && direction.getY()==
1 ) direction.setDown();
else return ;}Vector getNextPosition(){Vector newVector;newVector.setX(position.getX()+direction.getX());newVector.setY(position.getY()+direction.getY());
return newVector;}
};class Mouse:
public Cat
{
public :
Mouse ():
Cat (){;}
};class Labyrinth
{
private :
char lab[LENGTH][LENGTH];Cat tom;Mouse jerry;
public :
void read (){
int i,j;
char tpchar;Vector position;
for (i=
0 ;i<LENGTH;i++){
for (j=
0 ;j<LENGTH;j++){cin>>tpchar;
if (tpchar==
'C' ){lab[i][j]=
'.' ;position.setX(i);position.setY(j);tom.setPosition(position);}
else if (tpchar==
'M' ){lab[i][j]=
'.' ;position.setX(i);position.setY(j);jerry.setPosition(position);}
else lab[i][j]=tpchar;}}}
bool legal(Vector position){
if ( position.getX()<
0 || position.getX()>=LENGTH|| position.getY()<
0 || position.getY()>=LENGTH|| lab[position.getX()][position.getY()]==
'*' )
return false ;
return true ;}
int getDirectionId(Vector direction){
if (direction.getX()==-
1 && direction.getY()==
0 )
return 0 ;
else if (direction.getX()==
1 && direction.getY()==
0 )
return 1 ;
else if (direction.getX()==
0 && direction.getY()==-
1 )
return 2 ;
else if (direction.getX()==
0 && direction.getY()==
1 )
return 3 ;
else return -
1 ;}
bool isVisited(unsigned
short visited[LENGTH][LENGTH][LENGTH][LENGTH]){
int mouseDirection=getDirectionId(jerry.getDirection());
int catDirection=getDirectionId(tom.getDirection());
int bit=catDirection*
4 +mouseDirection;
int element=visited[tom.getPosition().getX()][tom.getPosition().getY()][jerry.getPosition().getX()][jerry.getPosition().getY()];
int bitElement=(element>>bit)%
2 ;
if (bitElement==
1 )
return true ;
else {visited[tom.getPosition().getX()][tom.getPosition().getY()][jerry.getPosition().getX()][jerry.getPosition().getY()]+=(
1 <<bit);
return false ;}}
int run(){
int cnt=
0 ;unsigned
short visited[LENGTH][LENGTH][LENGTH][LENGTH]={
0 };
while (
true ){
if (tom.getPosition()==jerry.getPosition())
return cnt;
if (isVisited(visited))
return -
1 ;
if (!legal(tom.getNextPosition()))tom.turnRight();
else tom.setPosition(tom.getNextPosition());
if (!legal(jerry.getNextPosition()))jerry.turnRight();
else jerry.setPosition(jerry.getNextPosition());cnt++;}
return -
1 ;}
};
int main()
{Labyrinth lab;lab.read();cout<<lab.run()<<endl;
return 0 ;
}
最后我們進行一個小結: 淺談ACM盲區: 1.界面友好 2.編程規范 (1)變量和函數的命名規范 (2)變量和函數的命名格式(駝峰式) (3)縮進 (4)注釋:盡量用英文來保證兼容性 (5)可移植性、函數封裝與模塊耦合 3.非實用方法 4.實用性編程 5.面向對象編程
總結
以上是生活随笔 為你收集整理的essay 浅谈ACM盲区(下) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。