前言
經(jīng)過四篇散文歇由,終于接觸到了指針相關(guān)知識點我不會C++,沒問題果港,跟凱哥一起學(四)接下來我們繼續(xù):
訪問結(jié)構(gòu)體成員
訪問一個結(jié)構(gòu)體的任何成員沦泌,我們使用 member access operator(成員訪問操作符):(.) 來訪問結(jié)構(gòu)體成 員。成員訪問操作符編碼為結(jié)構(gòu)變量名和我們要訪問結(jié)構(gòu)成員之間的一個點符號辛掠。使用關(guān)鍵字 struct 來定義結(jié) 構(gòu)類型的變量谢谦。
#include <iostream>
#include <cstring>
using namespace std;
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( ) {
struct Books Book1;// Declare Book1 of type Book
struct Books Book2;// Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info
cout << "Book 1 title : " << Book1.title <<endl;
cout << "Book 1 author : " << Book1.author <<endl;
cout << "Book 1 subject : " << Book1.subject <<endl;
cout << "Book 1 id : " << Book1.book_id <<endl;
// Print Book2 info
cout << "Book 2 title : " << Book2.title <<endl;
cout << "Book 2 author : " << Book2.author <<endl;
cout << "Book 2 subject : " << Book2.subject <<endl;
cout << "Book 2 id : " << Book2.book_id <<endl;
return 0; }
編譯和執(zhí)行上面的代碼,執(zhí)行結(jié)果如下:
Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700
結(jié)構(gòu)體指針
您可以定義結(jié)構(gòu)體指針萝衩,以一種定義指向其他變量的指針非常相似的方式
struct Books *struct_pointer;
現(xiàn)在回挽,您可以用上面定義的指針變量存儲一個結(jié)構(gòu)變量的地址。找到一個結(jié)構(gòu)變量的地址猩谊,把操作符 & 置于結(jié)構(gòu) 體名稱的前面千劈,如下所示:
struct_pointer = &Book1;
為了通過一個指向結(jié)構(gòu)的指針訪問結(jié)構(gòu)體成員,必須使用 -> 操作符牌捷,如下所示:
struct_pointer->title;
讓我們使用結(jié)構(gòu)指針重寫上面的例子墙牌,希望這將幫助你更容易理解這個概念:
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books *book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( ) {
struct Books Book1;// Declare Book1 of type Book
struct Books Book2;// Declare Book2 of type Book
// Book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// Book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
// Print Book1 info, passing address of structure
printBook( &Book1 );
// Print Book1 info, passing address of structure
printBook( &Book2 );
return 0; }
// This function accept pointer to structure as parameter.
void printBook( struct Books *book )
{
cout << "Book title : " << book->title <<endl;
cout << "Book author : " << book->author <<endl;
cout << "Book subject : " << book->subject <<endl;
cout << "Book id : " << book->book_id <<endl;
}
編譯和執(zhí)行上面的代碼,執(zhí)行結(jié)果如下:
Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700
struct和typedef struct的區(qū)別
在C語言中暗甥,結(jié)構(gòu)體的定義要用typedef struct喜滨,例如:
typedef struct Number{
int a;
int b;
}Num;
這里的Number和Num指的都是整個結(jié)構(gòu)體,在聲明結(jié)構(gòu)體變量的時候可以是
struct Number num1; //聲明結(jié)構(gòu)體變量的第一種方式
也可以是
Num num1; //聲明結(jié)構(gòu)體變量的第二種方式
也就是說Num==struct Number撤防。定義中的Number其實也可以省略虽风,這樣的話聲明變量就只能是第二種方式了:
typedef struct{ //去掉Number也對
int a;
int b;
}Num;
Num num1;
在C++中,typedef的使用和C中是一樣的:
typedef struct Number{ //去掉Number也對
int a;
int b;
}Num; //Num是一個結(jié)構(gòu)體類型寄月,Num=struct Number.
Num num1; //使用時需要先聲明結(jié)構(gòu)體變量
num1.a=10; //再訪問成員變量
在C++中還有一種更簡便的使用方法:
struct Number{
int a;
int b;
}Num; //Num是一個結(jié)構(gòu)體變量!!!!
Num.a=10; //使用時可以直接訪問成員變量
終于進入對象環(huán)節(jié)了
這里大家簡單過下辜膝,接觸過java面向?qū)ο蟮耐瑢W這里可以一秒掃過,遇到問題再回頭查驗漾肮。
類和對象内舟、C++ 類的定義
class Box {
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
訪問數(shù)據(jù)成員
類的對象的公共數(shù)據(jù)成員可以使用直接成員訪問操作符 . 訪問.
類與對象的細節(jié)
繼承
在面向?qū)ο缶幊讨凶钪匾母拍钪痪褪抢^承。繼承允許我們根據(jù)一個類來定義另一個類初橘,這使得創(chuàng)建和維護一
個應(yīng)用程序更加的容易。這也提供了一個重用代碼功能和快速實現(xiàn)的機會充岛。
當創(chuàng)建一個類保檐,不是寫全新的數(shù)據(jù)成員和成員函數(shù)的時候,程序員可以指定新類崔梗,這個類可以繼承現(xiàn)有類的成
員夜只。這個現(xiàn)有的類稱為基類,這個新類稱為派生類蒜魄。
繼承的概念其實是一種關(guān)系扔亥。例如场躯,哺乳動物是動物,狗是哺乳動物旅挤,因此狗是動物等等踢关。
基類和派生類
一個類可以繼承多個類,這就意味著它可以從多個基類中繼承數(shù)據(jù)和函數(shù)粘茄。為了定義一個派生類签舞,我們可以使用
一個類繼承列表來指定基類。一個類繼承列表指定一個或多個基類柒瓣,類繼承列表形式如下:
class derived-class: access-specifier base-class
在這里 access-specifier 是 public 儒搭、 protected 或者 private ,base-class 是之前定義的類的名稱芙贫。如果 不使用 access-specifier 搂鲫,那么在默認情況下它是私有的。
考慮一個基類的 shape 和其派生類 Rectangle 的繼承情況如下:
#include <iostream>
using namespace std;
// Base class
class Shape
{
public:
void setWidth(int w)
{
width = w; }
void setHeight(int h)
{
height = h;
} protected:
int width;
int height;
};
// Derived class
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
return 0; }
上面的代碼編譯和執(zhí)行時磺平,它產(chǎn)生以下結(jié)果:
Total area: 35
繼承方式
當從一個基類派生一個子類的時候,公共基類可以通過 public 魂仍,protected ,或者 private 方式被繼承褪秀。繼承 方式被 access-specifier 指定蓄诽,正如上面解釋的。
我們幾乎不使用protected或私有private 繼承媒吗,但public繼承是常用的仑氛。在使用不同類型的繼承的時候,應(yīng)用規(guī) 則如下:
? public 繼承:當從一個公有基類派生一個類的時候,基類的公有成員成為派生類的公有成員;基類的保護成 員成為派生類的保護成員闸英。一個基類的私有成員不能被派生類直接訪問锯岖,但可以通過調(diào)用基類的公有和保護 成員訪問基類的私有成員。
? protected 繼承:當從一個受保護的基類派生子類的時候,基類的公有和保護成員成為派生類的保護成員甫何。
? private 繼承:當從一個私有的基類派生子類的時候,基類的公有和保護成員成為派生類的私有成員出吹。
多繼承
一個C++類可以繼承多個類的成員,多繼承語法如下:
class derived-class: access baseA, access baseB....
在這里 access 是 public 辙喂,protected 捶牢,或者是 private ,并且每一個基類將有一個 access 類型巍耗,他們將由 逗號分隔開秋麸,如上所示。讓我們試試下面的例子:
#include <iostream>
using namespace std;
// Base class Shape
class Shape
{
public:
void setWidth(int w)
{
width = w; }
void setHeight(int h)
{
height = h; }
protected:
int width;
int height;
};
// Base class PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
// Derived class
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
// Print the total cost of painting
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0; }
上面的代碼編譯和執(zhí)行時炬太,它產(chǎn)生以下結(jié)果:
Total area: 35
Total paint cost: $2450
C++ 中的函數(shù)重載
C++ 允許在同一范圍內(nèi)對一個函數(shù)名或一個操作符指定多個定義灸蟆,分別被稱為函數(shù)重載和操作符重載。
重載聲明是在同一的范圍內(nèi)對先前已經(jīng)聲明的相同函數(shù)名的聲明亲族,除非這兩個聲明有不同的參數(shù)和明顯不同的定
義(實現(xiàn)方式)炒考。
當你調(diào)用一個重載的函數(shù)或操作符時可缚,編譯器通過比較用來調(diào)用函數(shù)或操作符的指定的參數(shù)類型來確定使用最合
適的定義。選擇最合適的重載函數(shù)或操作符的過程被稱為重載決議斋枢。
你可以在同一范圍內(nèi)對同一函數(shù)名有多個定義帘靡。函數(shù)的定義必須滿足參數(shù)類型不同或參數(shù)的數(shù)量不同或兩者都不
相同。你不能重載只有返回類型不同的函數(shù)聲明杏慰。
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
} };
int main(void)
{
printData pd;
// Call print to print integer
pd.print(5);
// Call print to print float
pd.print(500.263);
// Call print to print character
pd.print("Hello C++");
return 0; }
上面的代碼編譯和執(zhí)行時测柠,它產(chǎn)生以下結(jié)果:
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
C++ 中的運算符重載
你可以重新定義或重載的大部分 C++ 已有的操作符。因此缘滥,程序員可以像使用用戶自定義類型一樣使用操作 符轰胁。
重載操作符是一類函數(shù),它們就是對已有的運算符重新進行定義朝扼,賦予其另一種功能赃阀,以適應(yīng)不同的數(shù)據(jù)類 型。像任何其它函數(shù),重載運算符也有返回類型和參數(shù)列表擎颖。
C++ 中的運算符重載
Box operator+(const Box&);
聲明加法運算符可以用來使兩個 Box 對象相加并返回最終 Box 對象榛斯。大多數(shù)重載運算符可以被定義為普通非成 員函數(shù)或類成員函數(shù)。如果我們把上面的函數(shù)定義為一個類的非成員函數(shù),那么我們就必須為每個操作數(shù)傳兩個參 數(shù)如下:
Box operator+(const Box&, const Box&);
下面是通過使用成員函數(shù)來展示運算符重載的概念的示例搂捧。這里一個對象作為一個參數(shù)被傳遞驮俗,通過訪問這個對 象可以獲得參數(shù)的屬性,將調(diào)用這個操作符的對象可以通過使用 this 操作符獲得允跑,下面這個例子展示了這一 點:
#include <iostream>
using namespace std;
class Box {
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// Overload + operator to add two Box objects.
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
} private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
// Main function for the program
int main( )
{
Box Box1;// Declare Box1 of type Box
Box Box2;// Declare Box2 of type Box
Box Box3;// Declare Box3 of type Box
double volume = 0.0; // Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// volume of box 1
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// Add two object as follows:
Box3 = Box1 + Box2;
// volume of box 3
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0; }
上面的代碼編譯和執(zhí)行時王凑,它產(chǎn)生以下結(jié)果:
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
可重載/不可重載的運算符
不可以重載的運算符
多態(tài)
面向?qū)ο蠓浅V匾囊粋€概念:多態(tài)性意味著有多種形式。通常聋丝,多態(tài)發(fā)生在類之間存在層級關(guān)系且這些類有繼承關(guān)系的時候索烹。 C++ 多態(tài)性是指不同的對象發(fā)送同一個消息,不同對象對應(yīng)同一消息產(chǎn)生不同行為弱睦。 考慮下面的例子百姓,一個基類派生了其他的兩類:
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
int area() {
cout << "Parent class area :" <<endl;
return 0;
} };
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
} };
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// Main function for the program
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0; }
上面的代碼編譯和執(zhí)行時,它產(chǎn)生以下結(jié)果:
Parent class area
Parent class area
輸出結(jié)果不正確的原因是對函數(shù) area() 的調(diào)用被編譯器設(shè)置了一次况木,即在基類中定義的版本垒拢,這被稱為對函數(shù) 調(diào)用的靜態(tài)分辨或者靜態(tài)鏈接,靜態(tài)鏈接就是在程序被執(zhí)行之前函數(shù)調(diào)用是確定的火惊。這有時也被稱為早期綁 定子库,因為函數(shù) area() 在編譯程序期間是固定的。
但是現(xiàn)在矗晃,讓我們對程序做略微修改,并在 Shape 類中 area() 的聲明之前加關(guān)鍵字 virtual 宴倍,它看起來像這 樣:
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0; }
};
這輕微的修改后张症,前面的示例代碼編譯和執(zhí)行時仓技,它會產(chǎn)生以下結(jié)果:
Rectangle class area
Triangle class area
這一次,編譯器關(guān)注的是指針的內(nèi)容而不是它的類型俗他。因此脖捻,由于三角形和矩形類對象的地址被存儲在形狀類 中,各自的 area() 函數(shù)可以被調(diào)用兆衅。
正如你所看到的地沮,每個子類都有一個對 area() 函數(shù)的實現(xiàn)。通常多態(tài)就是這樣使用的羡亩。你有不同的類摩疑,它們都 有一個的相同名字的函數(shù),甚至有相同的參數(shù)畏铆,但是對這個函數(shù)有不同的實現(xiàn)雷袋。
虛函數(shù)
基類中的虛函數(shù)是一個使用關(guān)鍵字 virtual 聲明的函數(shù)。派生類中已經(jīng)對函數(shù)進行定義的情況下辞居,定義一個基類 的虛函數(shù)楷怒,就是要告訴編譯器我們不想對這個函數(shù)進行靜態(tài)鏈接。
我們所希望的是根據(jù)調(diào)用函數(shù)的對象的類型對程序中在任何給定指針中被調(diào)用的函數(shù)的選擇瓦灶。這種操作被稱為動
態(tài)鏈接鸠删,或者后期綁定。
純虛函數(shù)
可能你想把虛函數(shù)包括在基類中贼陶,以便它可以在派生類中根據(jù)該類的對象對函數(shù)進行重新定義刃泡,但在許多情況下,在基類中不能對虛函數(shù)給出有意義的實現(xiàn)每界。
我們可以改變基類中的虛函數(shù) area() 如下:
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
area() = 0
就是告訴編譯器上面的函數(shù)沒有函數(shù)體捅僵。上面的虛函數(shù)就被稱為純虛函數(shù)。