在C語言中,數據和函數(操作數據的方法)是沒有關聯機制的,它們被分開聲明和使用,這樣的語言叫做“程序性語言”,由一組分佈在各個以功能爲導向的算法所驅動,各個函數處理共同的外部數據。
例如,定義一個結構體
typedef struct Point {
int x;
int y;
}Point2d;
當需要對這個結構體對象進行處理時,就需要定義一個函數:
void print_point(const Point2d &pt) {
printf("(%d, %d)", pt.x, pt.y);
}
或者更高效地,定義一個宏:
#define PRINT_POINT(pt) printf("(%d, %d)", pt.x, pt.y);
當需要對其進行修改,就需要這樣做:
Point2d pt;
pt.x = 1;
pt.y = 2;
到了C++這裏,class機制可以允許你用獨立的“抽象數據類型”來實現一個Point2d:
class Point2d{
public:
Point2d(int x, int y) : x_(x), y_(y) { }
int x() const {return x_; }
int y() const {return y_; }
void setX(int x) {x_ = x; }
void setY(int y) {y_ = y; }
private:
int x_;
int y_;
};
inline ostream & operator << (ostream &os, const Point2d &pt) {
os << "(" << pt.x() << ", " << pt.y() << ")";
}
更具有通用性的,定義一組繼承關係的類,可以抽象出一維、二維和三維點:
class Point {
public:
Point(int x) : x_(x) { }
int x() const {return x_; }
void setX(int x) {x_ = x; }
protected:
int x_;
}
class Point2d : public Point{
public:
Point2d(int x, int y) : Point(x), y_(y) { }
int y() const {return y_; }
void setY(int y) {y_ = y; }
protected:
int y_;
};
class Point3d : public Point2d {
public:
Point3d(int x, int y, int z) : Point2d(x, y), z_(z) { }
int z() const {return z_; }
void setZ(int z) {z_ = z; }
protected:
int z_;
};
更通用的,使用模板類實現參數抽象化:
template <class T>
class Point3d : public Point2d {
public:
Point3d(T x, T y, T z) : x_(x), y_(y), z_(z) { }
T x() const {return x_; }
T y() const {return y_; }
T z() const {return z_; }
void setX(T x) {x_ = x; }
void setY(T y) {y_ = y; }
void setZ(T z) {z_ = z; }
protected:
T x_;
T y_;
T z_;
};
可見,C++和C,不僅僅在程序的風格上截然不同,在變成的思想上也是有明顯的差異:C++旨在實現事務“抽象”,更通用性能更龐大,C語言的優勢在於精簡(相對C++而言)。
很難說,要定義一個點,上述的使用C語言和C++來實現哪一種更可取,或者哪一種更好、更強!
加上封裝以後的空間成本
上述例子中,C++對Point2d的操作方式(在類中定義了一些方法),相對於C的結構體機制來說,增加了多少空間成本呢?答案是:沒有增加任何的空間成本!數據成員(data member)直接內含在每一個類對象中,這和C結構體是一樣的。至於成員函數,雖然被聲明在類的定義中,但是卻沒有出現在任何一個類對象中,每一個非內聯的成員函數(注意必須是非內聯)只會產生一個函數實體。
造成空間成本的情況
C++在這兩種情況下才會造成額外的空間負擔:
- 虛函數:執行期綁定的高效機制,實現C++的多態性
- 虛基類:多次出現在繼承體系中,但是隻保留一份共享實體的機制。
除此以外,在沒有充分的理由來說C++比C更龐大或臃腫。