最近在學(xué)習(xí)Hoops?? 的引擎(http://www.hoops3d.com )
模擬它的MVO架構(gòu),不過沒有原代碼,所以很難a
設(shè)計(jì)了一個(gè)交互繪圖基本類,
但是還有錯(cuò)誤,鼠標(biāo)左鍵點(diǎn)擊兩下
?winGDI.cpp中出錯(cuò)。
請(qǐng)大蝦指教一二。
我已經(jīng)在這個(gè)問題上花了很多的心思。
其中最重要的就是Painter抽象類的設(shè)計(jì)
他的子類QBufferDC繼承CDC
而SGView包含Painter指針,方便在SGView ::drawEntity調(diào)用。
SGObject - 對(duì)象的抽象類,也就是幾何對(duì)象
SGModel- 負(fù)責(zé)對(duì)象管理,沒有實(shí)現(xiàn)所有的功能,準(zhǔn)備用SceneTree來實(shí)現(xiàn)
SGView - 負(fù)責(zé)顯示SGModel中的數(shù)據(jù),關(guān)鍵的函數(shù)
void SGView::drawEntity(SGObject* pObj)
{
???pObj->draw(m_pPainter,this)
}
Painter - 封裝CDC的功能,見代碼
在CSGView創(chuàng)建的時(shí)候創(chuàng)建Painter對(duì)象
很可能這里有問題!!!!!
void CSGView::OnCreate(..)
{
?????CDC*?pDC =?GetDC();
???Painter* painter = new QBufferDC(pDC);
???m_pSGView->setPainter(painter);
}
MFC 相關(guān)的Document/View架構(gòu)
CSGDocument - 管理SGModel
CSGView - 和SGView建立聯(lián)系,并負(fù)責(zé)把windows的消息發(fā)送給SGView
見原代碼
SGActionManager - 負(fù)責(zé)工具的管理
SGBaseAction - 工具的抽象基類
SGActionDrawLine - 繪制直線的工具
源代碼連接:
http://www.shnenglu.com/Files/richardzeng/MVOTest.rar
我要設(shè)計(jì)的應(yīng)用程序其中的一個(gè)模塊就是封裝 windows GDI中的畫筆,畫刷等GDI object
把GDI object 再封裝成resource,以實(shí)現(xiàn)多種樣式多線條的畫筆及畫刷資源
畫筆,畫刷等資源繼承resource
為了避免發(fā)生資源泄露和resource的管理
設(shè)計(jì)ResourceManager類,負(fù)責(zé)資源的創(chuàng)建,加載和卸載以及刪除
兩個(gè)抽象類 Resource 和 ResourceManager
兩個(gè)具體類 ConcreateResource 和 ConcreateResourceManager
分別派生于上面的抽象類
以上設(shè)計(jì)是看了 OGRE 游戲引擎的資源管理部分,
對(duì)它的資源管理類ResourceManager不是很理解
resource 派生了pen,brush等類
pen類可以來自文件,也可以自己創(chuàng)建SubPen 添加到SubPenList中
ResourceManager 負(fù)責(zé)創(chuàng)建資源Resource
1. 如果我在抽象的 ResourceManager 聲明 createRes函數(shù),并返回基類resource
勢(shì)必會(huì)要強(qiáng)制轉(zhuǎn)換,然后在用到具體的Resource時(shí)候又要轉(zhuǎn)換回來
2. 如果我在具體類 ConcreateResourceManager 聲明 createConcreateRes函數(shù)
那么就白費(fèi)了我應(yīng)用設(shè)計(jì)模式設(shè)計(jì)這么多類
// abstract class for resource
class Resource{
public:
?// standard constructor
? Resource(const string& name, const string& group)
?:mName(name),mGroup(group){}
? ~Resource(){}
protected:
?// prevent default construct
? Resource():mName(""),mGroup(""){}
? string mName;
? string mGroup;
? static unsigned long mHandle;
};
// subclass of resource
// concreateResource such as PEN
class Pen:
?public Resource{
?Pen(const string& name, const string& group)
??:Resource(name,group){}
??~Pen(){}
? void loadfromFile(string& filename);
// add?into vector
? void addSubPen(SubPen* sub){
???? mSubPenList.push_back(sub);
}
public:
typedef std::vector<SubPen> SubPenList;
SubPenList mSubPenList;
};
class
// abstract class for resource manager
class ResourceManager{
public:
? ResourceManager(){}
? ~ResourceManager(){}
public:
// here , I cannot understand OGRE degsin
? Resource* createRes(const string& name,const string& group);
?// resource map
typedef std::map<string,Resource*> ResourceMap;
?? ResourceMap mResources;
};
// subclass ResourceManager
class ConcreateResourceManager
?:public ResourceManager
{
?ConcreateResourceManager(){}
?~ConcreateResourceManager(){}
????? // how can design here!!
?????? Pen* createPen(const string& name,const string& group){}
}
?
設(shè)計(jì)一個(gè)程序?qū)崿F(xiàn)如何保存一系列的SPen(如下定義)對(duì)象到文件,或者稱為序列化SPen collection
SPenCollection::Load和 Save函數(shù)實(shí)現(xiàn)打開畫筆文件(文件的內(nèi)容是一系列SPen對(duì)象)
// for example
?SPenCollection pc;
?pc.Load("C:\\1.pen");
我不知道如何序列化容器類對(duì)象,請(qǐng)大蝦指教。
// SPen object
class SPen : public CObject
{
?DECLARE_SERIAL(SPen)
public:
?SPen();
?virtual ~SPen();
public:
?int lineStyle;
?int lineWidth;
?COLORREF lineColor;
public:
?virtual void Serialize(CArchive& ar);
};
// SPen.cpp : 實(shí)現(xiàn)文件
//
#include "stdafx.h"
#include "ArchiveTest.h"
#include "SPen.h"
// SPen
IMPLEMENT_SERIAL(SPen,CObject,1)
SPen::SPen()
{
?lineStyle = PS_SOLID;
?lineWidth = 2;
?lineColor = RGB(255,0,0);
}
SPen::~SPen()
{
}
// SPen 成員函數(shù)
void SPen::Serialize(CArchive& ar)
{
?if (ar.IsStoring())
?{?// storing code
??ar<<lineStyle;
??ar<<lineWidth;
??ar<<lineColor;
?}
?else
?{?// loading code
??ar>>lineStyle;
??ar>>lineWidth;
??ar>>lineColor;
?}
}
///////////////////////////////////////
// 關(guān)鍵是要實(shí)現(xiàn)如何保存一系列的SPen對(duì)象
// load 和 save函數(shù)實(shí)現(xiàn)打開畫筆文件(文件的內(nèi)容是一系列SPen對(duì)象)
// for example
/** SPenCollection pc;
???pc.Load("C:\\1.pen");
?**/
#pragma once
// SPenCollection 命令目標(biāo)
#include "SPen.h"
#include <afxtempl.h>
class SPenCollection : public CObject
{
?DECLARE_SERIAL(SPenCollection)
public:
?SPenCollection();
?virtual ~SPenCollection();
?void AddPen(SPen* pen);
?void Load(CString strFileName);
?void Save(CString strFileName);
// CArray 不知道用得對(duì)不對(duì),請(qǐng)大蝦指教
?CArray<SPen*,SPen*> pens;
};
?
下面是Boost serialization 中的demo例子
為何寫了serialize 函數(shù)還寫個(gè)ostream<<
阿,
我對(duì)ostream 不是很了解,
我的印象是iostream 是在控制臺(tái)里輸入輸出的
/////////////////////////////////////////////////////////////////////////////
class gps_position
{
??? friend std::ostream & operator<<(std::ostream &os, const gps_position &gp);
??? friend class boost::serialization::access;
??? int degrees;
??? int minutes;
??? float seconds;
??? template<class Archive>
??? void serialize(Archive & ar, const unsigned int /* file_version */){
??????? ar & degrees & minutes & seconds;
??? }
public:
??? // every serializable class needs a constructor
??? gps_position(){};
??? gps_position(int _d, int _m, float _s) :
??????? degrees(_d), minutes(_m), seconds(_s)
??? {}
};
std::ostream & operator<<(std::ostream &os, const gps_position &gp)
{
??? return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"';
}
?最近想試試boost,下載了boost 1.33.1
我目前使用的是VC++2005,
首先編譯bjam, 不過用boost 1.33.1 \tools \jam-src 下的build.bat不用又從sf上下載了
最新的bjam,然后編譯bjam,倒是很簡(jiǎn)單很快就好生成bjam.exe
然后把bjam的路徑設(shè)置到path 環(huán)境變量中
一切都運(yùn)行正常。
我首先就編譯了boost -serialization
在命令行模式下
cd <boost-serialization 目錄>
運(yùn)行bjam "-sTOOLS=vc-8_0"
編譯完成后在boost 目錄下生成了bin 目錄C:\boost_1_33_1\bin\
我編譯的serialization lib 文件在這里
C:\boost_1_33_1\bin\boost\libs\serialization\build\boost_serialization.dll\vc-8_0\debug\threading-multi,當(dāng)然還有其它的lib,dll
首先設(shè)置vc++包含文件目錄C:\boost_1_33_1\
庫(kù)文件設(shè)置在C:\boost_1_33_1\bin\boost\libs\serialization\build\boost_serialization.dll\vc-8_0\debug\threading-multi,
(這個(gè)肯定不好,難道我需要一個(gè)lib文件就要在這里加一個(gè)路徑,因?yàn)榫幾g的lib文件太分散,沒有集中,不知道copy到一起是否可行)
然后我copy boost serialization 中demo代碼,
編譯demo.cpp,就提示 fatal error LNK1104: 無法打開文件“l(fā)ibboost_serialization-vc80-mt-gd-1_33_1.lib”
我想是不是lib文件的路徑不對(duì)阿,把要的libboost_serialization-vc80-mt-gd-1_33_1.lib 拷貝到C:\boost_1_33_1\libs
下還是不行,設(shè)置項(xiàng)目依賴文件也不行,
到底在vc++2005 中怎么設(shè)置boost的環(huán)境阿
我在VS2005中編譯Vector3D類出現(xiàn)
error C2662: “Vector3D::dotP”: 不能將“this”指針從“const Vector3D”轉(zhuǎn)換為“Vector3D &”
怎么樣改正呢,這個(gè)類也是看到別人這樣寫的,編譯也沒有錯(cuò)誤。
#pragma once
#define M_PI 3.141
#include <math.h>
class Vector3D{
?Vector3D(){x=y=z=0.0;}
?Vector3D(double vx, double vy,double vz=0.0){
??x = vx;
??y = vy;
??z = vz;
?}
?
?double magnitude() const{
??return sqrt(x*x+y*y+z*z);
?}
?double dotP(const Vector3D& v1,const Vector3D& v2){
??return (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z);
?}
?// get the vector angle
?double angle() const{
??double ret = 0.0;
??double m = magnitude();
??if (m>1.0e-6) {
//?問題出在這里!!!!
// ==============================
???double dp = dotP(*this,Vector3D(1.0,0.0));
//==============================
???if (dp/m>=1.0) {
????ret = 0.0;
???}
???else if (dp/m<-1.0) {
????ret = M_PI;
???}
???else {
????ret = acos( dp / m);
???}
???if (y<0.0) {
????ret = 2*M_PI - ret;
???}
??}
??return ret;
?}
protected:
?double x;
?double y;
?double z;
};#pragma once
#define M_PI 3.141
#include <math.h>
class Vector3D{
?Vector3D(){x=y=z=0.0;}
?Vector3D(double vx, double vy,double vz=0.0){
??x = vx;
??y = vy;
??z = vz;
?}
?
?double magnitude() const{
??return sqrt(x*x+y*y+z*z);
?}
?double dotP(const Vector3D& v1,const Vector3D& v2){
??return (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z);
?}
?// get the vector angle
?double angle() const{
??double ret = 0.0;
??double m = magnitude();
??if (m>1.0e-6) {
???double dp = dotP(*this,Vector3D(1.0,0.0));
???if (dp/m>=1.0) {
????ret = 0.0;
???}
???else if (dp/m<-1.0) {
????ret = M_PI;
???}
???else {
????ret = acos( dp / m);
???}
???if (y<0.0) {
????ret = 2*M_PI - ret;
???}
??}
??return ret;
?}
protected:
?double x;
?double y;
?double z;
};
這些東西在網(wǎng)上都很多了,但是我覺得他們的使用都不符合我的要求,所以自己動(dòng)手豐衣足食,寫一個(gè)自己能用的,夠用就好。
#include <iostream>
?
using namespace std;
?
//單件模板類
template<typename T> class Singleton
{
protected:
?
? static T* m_Instance;
?
? Singleton(){}
? virtual~Singleton(){}
?
public:
?
? //實(shí)例的獲得
? static T* Instance()
? {
??? if(m_Instance==0)
????? m_Instance=new T;
?
??? return m_Instance;
? }
?
? //單件類的釋放
? virtual void Release()
? {
??? if(m_Instance!=0)
??? {
????? delete m_Instance;
????? m_Instance=0;
??? }
? }
};
?
//單件模板測(cè)試類
class Test:public Singleton<Test>
{
? friend class Singleton<Test>; //聲明為友員,不然會(huì)出錯(cuò)
protected:
? Test()
? {
??? a=b=c=0;
? }
? virtual ~Test(){}
?
public :
?
? int a;
? int b;
? int c;
};
?
//初始化靜態(tài)成員。。。
template<> Test*Singleton<Test>::m_Instance=0;
?
?
//以下為測(cè)試代碼
void main()
{
? Test*t=Test::Instance();
?
? t->a=5;
? t->b=25;
? t->c=35;
? cout<<"t: a="<<t->a<<" b="<<t->b<<" c="<<t->c<<endl;
?
? Test*t2;
? t2=Test::Instance();
? cout<<"t2 a="<<t2->a<<" b="<<t2->b<<" c="<<t2->c<<endl;
?
? t2->Release();
}
|
我看到EffectiveC++2ed中函數(shù)返回對(duì)象中的說明感覺以后再也不想讓返回任何東西啦。比較怕。
但是有的時(shí)候不返回任何東西是不行的阿。
返回引用,返回指針,返回對(duì)象到底怎么寫?!
——————————————————————————————
下面是EC中的內(nèi)容
條款23: 必須返回一個(gè)對(duì)象時(shí)不要試圖返回一個(gè)引用
據(jù)說愛因斯坦曾提出過這樣的建議:盡可能地讓事情簡(jiǎn)單,但不要過于簡(jiǎn)單。在c++語(yǔ)言中相似的說法應(yīng)該是:盡可能地使程序高效,但不要過于高效。
一旦程序員抓住了“傳值”在效率上的把柄(參見條款22),他們會(huì)變得十分極端,恨不得挖出每一個(gè)隱藏在程序中的傳值操作。豈不知,在他們不懈地追求純粹的“傳引用”的過程中,他們會(huì)不可避免地犯另一個(gè)嚴(yán)重的錯(cuò)誤:傳遞一個(gè)并不存在的對(duì)象的引用。這就不是好事了。
看一個(gè)表示有理數(shù)的類,其中包含一個(gè)友元函數(shù),用于兩個(gè)有理數(shù)相乘:
class rational {
public:
? rational(int numerator = 0, int denominator = 1);
? ...
private:
? int n, d;????????????? // 分子和分母
friend
? const rational????????????????????? // 參見條款21:為什么
??? operator*(const rational& lhs,??? // 返回值是const
????????????? const rational& rhs)????
};
inline const rational operator*(const rational& lhs,
??????????????????????????????? const rational& rhs)
{
? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
很明顯,這個(gè)版本的operator*是通過傳值返回對(duì)象結(jié)果,如果不去考慮對(duì)象構(gòu)造和析構(gòu)時(shí)的開銷,你就是在逃避作為一個(gè)程序員的責(zé)任。另外一件很明顯的事實(shí)是,除非確實(shí)有必要,否則誰(shuí)都不愿意承擔(dān)這樣一個(gè)臨時(shí)對(duì)象的開銷。那么,問題就歸結(jié)于:確實(shí)有必要嗎?
答案是,如果能返回一個(gè)引用,當(dāng)然就沒有必要。但請(qǐng)記住,引用只是一個(gè)名字,一個(gè)其它某個(gè)已經(jīng)存在的對(duì)象的名字。無論何時(shí)看到一個(gè)引用的聲明,就要立即問自己:它的另一個(gè)名字是什么呢?因?yàn)樗厝贿€有另外一個(gè)什么名字(見條款m1)。拿operator*來說,如果函數(shù)要返回一個(gè)引用,那它返回的必須是其它某個(gè)已經(jīng)存在的rational對(duì)象的引用,這個(gè)對(duì)象包含了兩個(gè)對(duì)象相乘的結(jié)果。
但,期望在調(diào)用operator*之前有這樣一個(gè)對(duì)象存在是沒道理的。也就是說,如果有下面的代碼:
rational a(1, 2);??????????????? // a = 1/2
rational b(3, 5);??????????????? // b = 3/5
rational c = a * b;????????????? // c 為 3/10
期望已經(jīng)存在一個(gè)值為3/10的有理數(shù)是不現(xiàn)實(shí)的。如果operator* 一定要返回這樣一個(gè)數(shù)的引用,就必須自己創(chuàng)建這個(gè)數(shù)的對(duì)象。
一個(gè)函數(shù)只能有兩種方法創(chuàng)建一個(gè)新對(duì)象:在堆棧里或在堆上。在堆棧里創(chuàng)建對(duì)象時(shí)伴隨著一個(gè)局部變量的定義,采用這種方法,就要這樣寫operator*:
// 寫此函數(shù)的第一個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? rational result(lhs.n * rhs.n, lhs.d * rhs.d);
? return result;
}
這個(gè)方法應(yīng)該被否決,因?yàn)槲覀兊哪繕?biāo)是避免構(gòu)造函數(shù)被調(diào)用,但result必須要象其它對(duì)象一樣被構(gòu)造。另外,這個(gè)函數(shù)還有另外一個(gè)更嚴(yán)重的問題,它返回的是一個(gè)局部對(duì)象的引用,關(guān)于這個(gè)錯(cuò)誤,條款31進(jìn)行了深入的討論。
那么,在堆上創(chuàng)建一個(gè)對(duì)象然后返回它的引用呢?基于堆的對(duì)象是通過使用new產(chǎn)生的,所以應(yīng)該這樣寫operator*:
// 寫此函數(shù)的第二個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? rational *result =
??? new rational(lhs.n * rhs.n, lhs.d * rhs.d);
? return *result;
}
首先,你還是得負(fù)擔(dān)構(gòu)造函數(shù)調(diào)用的開銷,因?yàn)閚ew分配的內(nèi)存是通過調(diào)用一個(gè)適當(dāng)?shù)臉?gòu)造函數(shù)來初始化的(見條款5和m8)。另外,還有一個(gè)問題:誰(shuí)將負(fù)責(zé)用delete來刪除掉new生成的對(duì)象呢?
實(shí)際上,這絕對(duì)是一個(gè)內(nèi)存泄漏。即使可以說服operator*的調(diào)用者去取函數(shù)返回值地址,然后用delete去刪除它(絕對(duì)不可能——條款31展示了這樣的代碼會(huì)是什么樣的),但一些復(fù)雜的表達(dá)式會(huì)產(chǎn)生沒有名字的臨時(shí)值,程序員是不可能得到的。例如:
rational w, x, y, z;
w = x * y * z;
兩個(gè)對(duì)operator*的調(diào)用都產(chǎn)生了沒有名字的臨時(shí)值,程序員無法看到,因而無法刪除。(再次參見條款31)
也許,你會(huì)想你比一般的熊——或一般的程序員——要聰明;也許,你注意到在堆棧和堆上創(chuàng)建對(duì)象的方法避免不了對(duì)構(gòu)造函數(shù)的調(diào)用;也許,你想起了我們最初的目標(biāo)是為了避免這種對(duì)構(gòu)造函數(shù)的調(diào)用;也許,你有個(gè)辦法可以只用一個(gè)構(gòu)造函數(shù)來搞掂一切;也許,你的眼前出現(xiàn)了這樣一段代碼:operator*返回一個(gè)“在函數(shù)內(nèi)部定義的靜態(tài)rational對(duì)象”的引用:
// 寫此函數(shù)的第三個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? static rational result;????? // 將要作為引用返回的
?????????????????????????????? // 靜態(tài)對(duì)象
? lhs和rhs 相乘,結(jié)果放進(jìn)result;
? return result;
}
這個(gè)方法看起來好象有戲,雖然在實(shí)際實(shí)現(xiàn)上面的偽代碼時(shí)你會(huì)發(fā)現(xiàn),不調(diào)用一個(gè)rational構(gòu)造函數(shù)是不可能給出result的正確值的,而避免這樣的調(diào)用正是我們要談?wù)摰闹黝}。就算你實(shí)現(xiàn)了上面的偽代碼,但,你再聰明也不能最終挽救這個(gè)不幸的設(shè)計(jì)。
想知道為什么,看看下面這段寫得很合理的用戶代碼:
bool operator==(const rational& lhs,????? // rationals的operator==
??????????????? const rational& rhs);???? //
rational a, b, c, d;
...
if ((a * b) == (c * d)) {
? 處理相等的情況;
} else {
? 處理不相等的情況;
}
看出來了嗎?((a*b) == (c*d)) 會(huì)永遠(yuǎn)為true,不管a,b,c和d是什么值!
用等價(jià)的函數(shù)形式重寫上面的相等判斷語(yǔ)句就很容易明白發(fā)生這一可惡行為的原因了:
if (operator==(operator*(a, b), operator*(c, d)))
注意當(dāng)operator==被調(diào)用時(shí),總有兩個(gè)operator*剛被調(diào)用,每個(gè)調(diào)用返回operator*內(nèi)部的靜態(tài)rational對(duì)象的引用。于是,上面的語(yǔ)句實(shí)際上是請(qǐng)求operator==對(duì)“operator*內(nèi)部的靜態(tài)rational對(duì)象的值”和“operator*內(nèi)部的靜態(tài)rational對(duì)象的值”進(jìn)行比較,這樣的比較不相等才怪呢!
幸運(yùn)的話,我以上的說明應(yīng)該足以說服你:想“在象operator*這樣的函數(shù)里返回一個(gè)引用”實(shí)際上是在浪費(fèi)時(shí)間。但我沒幼稚到會(huì)相信幸運(yùn)總會(huì)光臨自己。一些人——你們知道這些人是指誰(shuí)——此刻會(huì)在想,“唔,上面那個(gè)方法,如果一個(gè)靜態(tài)變量不夠用,也許可以用一個(gè)靜態(tài)數(shù)組……”
請(qǐng)就此打住!我們難道還沒受夠嗎?
我不能讓自己寫一段示例代碼來太高這個(gè)設(shè)計(jì),因?yàn)榧词怪槐в猩厦孢@種想法都足以令人感到羞愧。首先,你必須選擇一個(gè)n,指定數(shù)組的大小。如果n太小,就會(huì)沒地方儲(chǔ)存函數(shù)返回值,這和我們前面否定的那個(gè)“采用單個(gè)靜態(tài)變量的設(shè)計(jì)”相比沒有什么改進(jìn)。如果n太大,就會(huì)降低程序的性能,因?yàn)楹瘮?shù)第一次被調(diào)用時(shí)數(shù)組中每個(gè)對(duì)象都要被創(chuàng)建。這會(huì)帶來n個(gè)構(gòu)造函數(shù)和n個(gè)析構(gòu)函數(shù)的開銷,即使這個(gè)函數(shù)只被調(diào)用一次。如果說"optimization"(最優(yōu)化)是指提高軟件的性能的過程, 那么現(xiàn)在這種做法簡(jiǎn)直可以稱為"pessimization"(最差化)。最后,想想怎么把需要的值放到數(shù)組的對(duì)象中以及需要多大的開銷?在對(duì)象間傳值的最直接的方法是通過賦值,但賦值的開銷又有多大呢?一般來說,它相當(dāng)于調(diào)用一個(gè)析構(gòu)函數(shù)(摧毀舊值)再加上調(diào)用一個(gè)構(gòu)造函數(shù)(拷貝新值)。但我們現(xiàn)在的目標(biāo)正是為了避免構(gòu)造和析構(gòu)的開銷啊!面對(duì)現(xiàn)實(shí)吧:這個(gè)方法也絕對(duì)不能選用。
所以,寫一個(gè)必須返回一個(gè)新對(duì)象的函數(shù)的正確方法就是讓這個(gè)函數(shù)返回一個(gè)新對(duì)象。對(duì)于rational的operator*來說,這意味著要不就是下面的代碼(就是最初看到的那段代碼),要不就是本質(zhì)上和它等價(jià)的代碼:
inline const rational operator*(const rational& lhs,
??????????????????????????????? const rational& rhs)
{
? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
的確,這會(huì)導(dǎo)致“operator*的返回值構(gòu)造和析構(gòu)時(shí)帶來的開銷”,但歸根結(jié)底它只是用小的代價(jià)換來正確的程序運(yùn)行行為而已。況且,你所擔(dān)心的開銷還有可能永遠(yuǎn)不會(huì)出現(xiàn):和所有程序設(shè)計(jì)語(yǔ)言一樣,c++允許編譯器的設(shè)計(jì)者采用一些優(yōu)化措施來提高所生成的代碼的性能,所以,在有些場(chǎng)合,operator*的返回值會(huì)被安全地除去(見條款m20)。當(dāng)編譯器采用了這種優(yōu)化時(shí)(當(dāng)前大部分編譯器這么做),程序和以前一樣繼續(xù)工作,只不過是運(yùn)行速度比你預(yù)計(jì)的要快而已。
以上討論可以歸結(jié)為:當(dāng)需要在返回引用和返回對(duì)象間做決定時(shí),你的職責(zé)是選擇可以完成正確功能的那個(gè)。至于怎么讓這個(gè)選擇所產(chǎn)生的代價(jià)盡可能的小,那是編譯器的生產(chǎn)商去想的事。
摘要: 在
google
上搜了很久的關(guān)于
Doxygen
使用方法的咚咚,只不過都是英文,而且都很多的規(guī)則。實(shí)際上大家只需要告訴基本的規(guī)則就可以。下面是我對(duì)
Doxygen
的摸索
?
首先熟知
Do...
閱讀全文
最近在看吉林大學(xué)的C程序設(shè)計(jì)的課件,有一章講到這個(gè)函數(shù)動(dòng)手寫了一下。
題目:
編寫一個(gè)Insert函數(shù)實(shí)現(xiàn)在字符串s中的第i個(gè)位置插入字符串s1;
在VC++2005中編譯這段程序沒有任何的Error和warning但是運(yùn)行就會(huì)錯(cuò)誤,不知道為什么阿,請(qǐng)高手指點(diǎn)一二。
#include "stdafx.h"
#include <iostream>
using namespace std;
void Insert(char *s, char *s1, int i)
{
?char *p,*q;
?p = s + strlen(s); // p?指向s的末尾+1
?q = p + strlen(s1);?//q 指向新構(gòu)造的字符串的\0?
?*q = '\0';
?//?
?for(p--,q--;p>=s+i-1;)
?{
??*(p--) = *(q--);
?}
?//
?for(p=s+i-1;*s1;)
?{
??*(p++) = *(s1++);
?}
}
int _tmain(int argc, _TCHAR* argv[])
{
?char *s = "Student";
?char *s1 = "Teacher";
?Insert(s,s1,3);
// 期待的輸出是StuTeacherdent;
?cout<<s;
?return 0;
}
// 還有我如果把insert函數(shù)改成下面的應(yīng)該也是可以的吧
void Insert2(char *s, char *s1, int i)
{
?char *p,*q;
?p = s + strlen(s); // p?指向s的末尾+1
?q = p + strlen(s1);?//q 指向新構(gòu)造的字符串的\0?
?*q = '\0';
?//?
?for(p--,q--;p>=s+i-1;)
?{
??*p-- = *q--;
?}
?//
?for(p=s+i-1;*s1;)
?{
??*p++ = *s1++;
?}
}