- 浏览: 508784 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jkxydp:
算法运行的结果根本就不对。
BM算法. -
soarwindzhang:
感谢博主的分享,我今天看了您的UFSET非递归的路径压缩时感觉 ...
并查集 -
zhangning290:
楼主好像只考虑了坏字符规则,。没有考虑好后缀
BM算法. -
lsm0622:
文字描述有错误 误导新学者
求有向图的强连通分量(scc):Tarjan算法 -
knightchen:
博主,你太强了!这篇文章对我学习C++多线程很有帮助!谢谢
并发学习之一_windows下ZThread在CodeBlocks上的安装与配置
1,先看个例子:
class Person { ... };
class BankAccount
{
public:
BankAccount(const Person *primaryOwner,
const Person *jointOwner);
virtual ~BankAccount();
virtual void makeDeposit(double amount) = 0;
virtual void makeWithdrawal(double amount) = 0;
virtual double balance() const = 0;
...
};
class SavingsAccount: public BankAccount
{
public:
SavingsAccount(const Person *primaryOwner,
const Person *jointOwner);
~SavingsAccount();
void creditInterest(); // add interest to account
...
};
使用:
list<BankAccount*> allAccounts;
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
(*p)->creditInterest(); // error!
}
错误:creditInterest在BankAccounts中不存在.
可行的纠正:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
static_cast<SavingsAccount*>(*p)->creditInterest(); //downcast
}
注:转型(cast)之于程序员,犹如苹果之于夏娃.
2,如果又有一个新的账户加入.
class CheckingAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
我们这时候必须这么做:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
if (*p points to a SavingsAccount)
static_cast<SavingsAccount*>(*p)->creditInterest();
else
static_cast<CheckingAccount*>(*p)->creditInterest();
}
根据型别做事,这不是C++的精神,应该使用虚拟函数.
class BankAccount { ... }; // as above
// new class representing accounts that bear interest
class InterestBearingAccount: public BankAccount
{
public:
virtual void creditInterest() = 0; //提供接口
...
};
class SavingsAccount: public InterestBearingAccount
{
... // as above
};
class CheckingAccount: public InterestBearingAccount
{
... // as above
};
如下图所示:
这时候,你可以这么使用:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
static_cast<InterestBearingAccount*>(*p)->creditInterest();
}
3,还有另外一种解决的办法:
class BankAccount
{
public:
virtual void creditInterest() {} //基类提供一个什么都不做的缺省实现
...
};
class SavingsAccount: public BankAccount { ... };
class CheckingAccount: public BankAccount { ... };
list<BankAccount*> allAccounts;// look ma, no cast!
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
(*p)->creditInterest();
}
4,总结:为了摆脱downcast,不论花多少努力都是值得的.
但是偶尔还是无法摆脱downcast.
例如:当我们无权改变BankAccount, SavingsAccount, 或 allAccounts的定义.
这时候,相对于static_cast,还有个比较好的办法:"safe downcasting"(安全向下转型)
使用dynamic_cast,如果失败,会传回null指针.
回到一开始的地方:
class Person { ... };
class BankAccount
{
public:
BankAccount(const Person *primaryOwner,
const Person *jointOwner);
virtual ~BankAccount();
virtual void makeDeposit(double amount) = 0;
virtual void makeWithdrawal(double amount) = 0;
virtual double balance() const = 0;
...
};
class SavingsAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
class CheckingAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
使用:
list<BankAccount*> allAccounts;
void error(const string& msg);
//至少可以保证downcast失败时,可以侦测到.
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
if (SavingsAccount *psa = dynamic_cast<SavingsAccount*>(*p))
{
psa->creditInterest();
}
else if (CheckingAccount *pca = dynamic_cast<CheckingAccount*>(*p))
{
pca->creditInterest();
}
// uh oh — unknown account type
else
{
error("Unknown account type!");
}
}
注:downcast必然导致if-then-else风格,比起虚函数,拙劣之极.
万不得已,不要这么使用.
class Person { ... };
class BankAccount
{
public:
BankAccount(const Person *primaryOwner,
const Person *jointOwner);
virtual ~BankAccount();
virtual void makeDeposit(double amount) = 0;
virtual void makeWithdrawal(double amount) = 0;
virtual double balance() const = 0;
...
};
class SavingsAccount: public BankAccount
{
public:
SavingsAccount(const Person *primaryOwner,
const Person *jointOwner);
~SavingsAccount();
void creditInterest(); // add interest to account
...
};
使用:
list<BankAccount*> allAccounts;
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
(*p)->creditInterest(); // error!
}
错误:creditInterest在BankAccounts中不存在.
可行的纠正:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
static_cast<SavingsAccount*>(*p)->creditInterest(); //downcast
}
注:转型(cast)之于程序员,犹如苹果之于夏娃.
2,如果又有一个新的账户加入.
class CheckingAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
我们这时候必须这么做:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
if (*p points to a SavingsAccount)
static_cast<SavingsAccount*>(*p)->creditInterest();
else
static_cast<CheckingAccount*>(*p)->creditInterest();
}
根据型别做事,这不是C++的精神,应该使用虚拟函数.
class BankAccount { ... }; // as above
// new class representing accounts that bear interest
class InterestBearingAccount: public BankAccount
{
public:
virtual void creditInterest() = 0; //提供接口
...
};
class SavingsAccount: public InterestBearingAccount
{
... // as above
};
class CheckingAccount: public InterestBearingAccount
{
... // as above
};
如下图所示:
这时候,你可以这么使用:
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
static_cast<InterestBearingAccount*>(*p)->creditInterest();
}
3,还有另外一种解决的办法:
class BankAccount
{
public:
virtual void creditInterest() {} //基类提供一个什么都不做的缺省实现
...
};
class SavingsAccount: public BankAccount { ... };
class CheckingAccount: public BankAccount { ... };
list<BankAccount*> allAccounts;// look ma, no cast!
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
(*p)->creditInterest();
}
4,总结:为了摆脱downcast,不论花多少努力都是值得的.
但是偶尔还是无法摆脱downcast.
例如:当我们无权改变BankAccount, SavingsAccount, 或 allAccounts的定义.
这时候,相对于static_cast,还有个比较好的办法:"safe downcasting"(安全向下转型)
使用dynamic_cast,如果失败,会传回null指针.
回到一开始的地方:
class Person { ... };
class BankAccount
{
public:
BankAccount(const Person *primaryOwner,
const Person *jointOwner);
virtual ~BankAccount();
virtual void makeDeposit(double amount) = 0;
virtual void makeWithdrawal(double amount) = 0;
virtual double balance() const = 0;
...
};
class SavingsAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
class CheckingAccount: public BankAccount
{
public:
void creditInterest(); // add interest to account
...
};
使用:
list<BankAccount*> allAccounts;
void error(const string& msg);
//至少可以保证downcast失败时,可以侦测到.
for (list<BankAccount*>::iterator p = allAccounts.begin(); p != allAccounts.end(); ++p)
{
if (SavingsAccount *psa = dynamic_cast<SavingsAccount*>(*p))
{
psa->creditInterest();
}
else if (CheckingAccount *pca = dynamic_cast<CheckingAccount*>(*p))
{
pca->creditInterest();
}
// uh oh — unknown account type
else
{
error("Unknown account type!");
}
}
注:downcast必然导致if-then-else风格,比起虚函数,拙劣之极.
万不得已,不要这么使用.
发表评论
-
条款43:明智地使用多继承
2010-06-08 09:33 14111,多继承带来的一个根本性的复杂性:模棱两可. 例如: # ... -
条款44:说出你的意思并了解你所说的每一句话
2010-06-08 09:30 8091,彻底了解不同的面向对象架构在C++中的意义. 2,声明一 ... -
条款30:避免写出member function,传回一个non-const function或reference并指向private或protect成员
2010-06-08 09:29 12271,先看一个例子: class Address { ... } ... -
条款4:尽量使用C++风格的注释形式
2010-06-07 09:49 7551,抛弃"/*...*/",改用" ... -
条款2:尽量以<iostream>取代<stdio.h>
2010-06-01 10:36 10091,scanf和printf的缺点:不具有型别安全(type- ... -
条款1:尽量以const和inline取代#define
2010-06-01 10:35 9561,意思就是"尽量以编译器(compiler)&qu ... -
条款42:明智地使用private inheritance(私有继承)
2010-05-29 17:51 10041,先搞清楚private inheritance的行为: ( ... -
条款41:区分inheritance和template
2010-05-29 17:50 7041,首先考虑一个问题: 型别T会影响class的行为吗? 如果 ... -
条款40:通过layering技术来模塑"有一个"(has-a)或"根据某物实现(is-implemented-in-terms-of)"
2010-05-29 17:48 7991,所谓laying,就是以一个class为本,建立另外一个c ... -
条款38:绝对不要重新定义继承而来的缺省参数值
2010-05-29 17:48 8111,首先可以安全的把问题讨论局限于"继承一个带有缺省 ... -
条款37:绝对不要重新定义继承而来的非虚拟函数
2010-05-29 17:47 7641,先看个例子: class B { public: vo ... -
条款36:区分接口继承和实现继承
2010-05-29 17:46 8791,public继承分为两类:接口继承和实现继承. 这两种继承 ... -
条款35:确定你的public继承,模塑出"isa"的关系
2010-05-29 17:46 9971,C++面向对象程序设计最重要的原则: public继承意味 ... -
条款29:避免传回内部数据的handles
2010-05-28 10:35 13891,考虑下面的代码: class string { oper ... -
条款28:尝试切割global namesapce
2010-05-28 10:34 7101,namesapce的使用 namespace std{ ... -
条款50:加强自己对C++的了解
2010-05-25 11:46 8931,只推荐两本书: (1)D&E: The Desig ... -
条款49:尽量让自己熟悉C++标准库
2010-05-25 11:46 8061,标准库的每一样东西几乎都在namespace std中,然 ... -
条款48:不要对编译器的警告视而不见
2010-05-25 11:45 7921,在你忽略一个警告之前,你必须精确了解编译器企图告诉你的是什 ... -
条款47:使用non-local static objects之前先确定它已有初值
2010-05-25 11:45 8581,当一个编译单元内某对象的初始化动作,与另一个编译单元内某对 ... -
条款26:防卫潜伏的ambiguity状态
2010-05-25 11:44 7541, class B; class A { public: ...
相关推荐
- **目的**: 避免在代码中出现显式的向下转型,提高安全性。 - **步骤**: 创建一个新方法来处理向下转型;在该方法中检查类型,并返回转换后的对象。 14. **封装值域 (Encapsulate Field)** - **定义**: 将类中...
而`downcast`就是一款专为播客爱好者设计的Python实用程序,它可以帮助用户方便地下载播客节目,让用户在离线状态下也能享受丰富的音频内容。 `downcast`的核心功能在于其强大的播客抓取和下载能力。它利用Python的...
例如,“AppName”键可能在英文版的.strings文件中对应“Downcast”,而在法文版中则对应“Downcast (version française)”。 三、.strings文件结构 在downcast-localization-master文件夹中,我们可以看到多语言...
13. **Encapsulate Downcast(封装向下转型动作)** - 描述:封装向下转型的动作,提高代码的健壮性。 - 场景:当需要频繁进行类型转换时使用。 14. **Encapsulate Field(封装字段)** - 描述:将类的字段...
- **Encapsulate Downcast (封装“向下转型”动作):**减少类型转换错误的风险。 - **Encapsulate Field (封装字段):**保护类的内部状态不受外部干扰。 - **Extract Class (提取类):**从现有类中分离出新的类。 - ...
它们通常用于编译时断言和类型安全的向下转型,这可以帮助程序员避免运行时错误。 4. Operators:在Boost的运算符库中,可以找到各种运算符的辅助函数。虽然C++标准库提供了一些运算符重载的机制,但Boost库在此...
- **polymorphic_downcast**:用于向下转型,提供类型安全检查。 - **numeric_cast**:提供安全的数值类型转换。 - **lexical_cast**:实现字符串和其他基本类型的相互转换。 #### 四、工具类(Library 3: Utility...
Type-Safe Downcast(保证安全的向下转型操作) Type-Safe Dynamic Cast(保证安全的动态转型) References并不是Pointers Typeid运算符 7.4 效率有了,弹性呢? 动态共享函数库(Dynamic Shared Libraries) 共享...
#### 3.13 Encapsulate Downcast(封装“向下转型”动作) 通过创建一个安全的接口来执行向下转型操作,避免直接使用强制转换,从而提高代码的安全性。 #### 3.14 Encapsulate Field(封装值域) 将类中的属性封装...
Downcast的设计理念可能是为了提供一个快速、高效且易于维护的发布环境,避免复杂的后台编辑器和冗余的功能,让用户专注于内容的创作。使用Markdown的好处在于,其语法简洁,易于学习,同时还能保持源代码的整洁,...