重溫《Inside The C++ Object Model》(1) --關于對象
來源:程序員人生 發布時間:2015-01-15 08:50:26 閱讀次數:3138次
C/C++ 編程風格
//1.C風格(結構化程序設計):數據和函數(操作)沒有任何關聯性
typedef struct Point3d
{
float x;
float y;
float z;
} Point3d_t;
void
Point3d_print(const Point3d_t *pd)
{
printf("%g, %g, %g
", pd->x, pd->y, pd->z);
}
//2.基于對象(Object-Base):提供抽象數據類型(ADT)來支持封裝
class Point3d
{
friend ostream &operator<<(ostream &os, const Point3d &pt);
public:
Point3d(float x = 0.0, float y = 0.0, float z = 0.0):
_x(x), _y(y), _z(z) {}
float x()
{
return _x;
}
float y()
{
return _y;
}
float z()
{
return _z;
}
void x(float xval)
{
_x = xval;
}
//etc...
private:
float _x;
float _y;
float _z;
};
inline ostream &
operator<<(ostream &os, const Point3d &pt)
{
return os << "( " << pt._x << ", " << pt._y << ", "
<< pt._z << " )";
}
//3.面向對象(Object-Oriented-Model):提供繼承和多態
class Point
{
public:
Point(float x = 0.0):
_x(x) {}
float x()
{
return _x;
}
void x(float xValue)
{
_x = xValue;
}
protected:
float _x;
};
class Point2d : public Point
{
public:
Point2d(float x = 0.0, float y = 0.0):
Point(x), _y(y) {}
float y()
{
return _y;
}
void y(float yValue)
{
_y = yValue;
}
protected:
float _y;
};
class Point3d : public Point2d
{
friend inline ostream &
operator<<(ostream &os, const Point3d &pt);
public:
Point3d(float x = 0.0, float y = 0.0, float z = 0.0):
Point2d(x, y), _z(z) {}
float z()
{
return _z;
}
void z(float zValue)
{
_z = zValue;
}
private:
float _z;
};
inline ostream &
operator<<(ostream &os, const Point3d &pt)
{
return os << "( " << pt._x << ", " << pt._y << ", "
<< pt._z << " )";
}
//4.面向泛型:提供模板提供類型無關化的編程風格
//示例(1):僅提供類型參數化
template <typename Type>
class Point3d
{
public:
Point3d(Type x = 0.0, Type y = 0.0, Type z = 0.0):
_x(x), _y(y), _z(z) {}
Type x()
{
return _x;
}
Type y()
{
return _y;
}
Type z()
{
return _z;
}
void x(const Type &xval)
{
_x = xval;
}
//etc...
private:
Type _x;
Type _y;
Type _z;
};
//示例(2):同時提供類型和數目(int dim)參數化
template <typename Type, int dim>
class Point
{
public:
Point() {}
Point(Type coordes[dim])
{
for (int index = 0; index < dim; ++index)
{
_coordes[index] = coordes[index];
}
}
const Type &operator[](int index) const
{
assert(index < dim && index >= 0);
return _coordes[index];
}
private:
Type _coordes[dim];
};
template <typename Type, int dim>
inline ostream &operator<<(ostream &os, const Point< Type, dim > &pt)
{
os << "( ";
for (int i = 0; i < dim; ++i)
os << pt[i] << ", ";
os << ")";
return os;
}
//測試
int array[] = {11,12,333};
Point<int, 3> point(array);
cout << point << endl;
cout << point[2] << endl;
小結:C++加上封裝的布局本錢
(1)3個data-member[數據成員]直接內含在每個class-object[對象]當中,猶如C-Struct1樣;
(2)Member-function雖然存在于class的聲明中, 卻不出現在object當中, 每個non-inline member function[非inline的成員函數]只會誕生1個函數實體;
(3)而inline member function會在其每個使用者身上產生1個函數實體.
C++對象模型
1.所有的數據成員(static 數據成員除外)寄存在每個對象當中;
2.[1]static 數據成員,[2]成員函數(不管是static/non-static)寄存在所有對象以外;
3.對virtual-functions, 每個對象都有1個vptr(指向1個vtbl(包括type_info object, virtual functions)).

因此:內存中對象的大小
(1)其non-static data member 的總和大小
(2)加上任何alignment(內存對其)的需求而彌補上去的空間[可能存在于members中間, 也可能存在于集合體邊界];
(3)加上支持virtual[vptr]而由內部產生的任何額外負擔.
//測試
class Point1
{
};
class Point2
{
private:
int number;
};
class Point3
{
public:
Point3(int _number = 0): number(_number) {}
~Point3() {}
static void showCount()
{
std::cout << "Point3_count = " << Point3_count << std::endl;
}
private:
static int Point3_count;
private:
int number;
};
class Point4
{
public:
virtual ~Point4();
private:
int number;
};
int main()
{
cout << sizeof(Point1) << endl;
cout << sizeof(Point2) << endl;
cout << sizeof(Point3) << endl;
cout << sizeof(Point4) << endl;
}
對象在內存中的布局
Derived Class 的Object 和 Pointer布局(以下圖)

(其實ZooAnimal subobject 的布局有些毛病, string類型在現代C++中只占4個字節, 因此ZooAnimal subobject所占的內存空間唯一12字節, 而不是圖中的16字節)
說明:
(1)pointer & reference 都只需1個字長(x86_32中為4個字節)的空間;
(2)派生類對象中:基類子對象與派生類子對象在內存中的位置是相鄰的.
//測試
class ZooAnimal
{
public:
ZooAnimal() {}
virtual ~ZooAnimal() {}
virtual void rotate() {}
protected:
int loc;
string name;
};
class Bear : public ZooAnimal
{
public:
Bear() {}
~Bear() {}
void rotate()
{
}
protected:
enum Dances
{
//...
};
Dances dances_known;
int cell_block;
};
int main()
{
Bear b;
ZooAnimal *pz = &b;
Bear *pb = &b;
cout << "Pointer..." << endl;
cout << sizeof(pz) << endl;
cout << sizeof(pb) << endl;
cout << "
Object..." << endl;
cout << sizeof(*pz) << endl;
cout << sizeof(*pb) << endl;
cout << "
Class..." << endl;
cout << sizeof(ZooAnimal) << endl;
cout << sizeof(Bear) << endl;
}
測試說明:
pb 所涵蓋的地址包括了全部Bear Object, 而 pz只包括了Bear Object中的ZooAnimal SubObject!
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈