【effective c++读书笔记】【第6章】继承与面向对象设计(4)

条款39:明智而审慎的使用private继承
1、如果classes之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象。

例子:

#include<iostream>
#include<string>
using namespace std;

class Person{
protected:
	string name;
};
class Student :private Person{
private:
	string schoolName;
};
void eat(const Person& p){
	cout << "eat" << endl;
}

int main(){
	Person p;
	Student s;
	eat(p);
	//eat(s); //错误

	system("pause");
	return 0;
}

2、由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protectedpublic属性。
3private继承意味着implemented-in-terms-of(根据某物实现出)。复合的意义也是如此。如何在两者间取舍?尽可能使用复合,必要时才使用private继承。必要是指a、当protected成员或virtual函数牵扯进来的时候,b、当空间方面的利害关系足以踢翻private继承的支柱时。
4、与复合比,private继承在空间上可以使空白基类最优化。
例子:
#include<iostream>
using namespace std;

class Empty{};
class HoldAnInt{
private:
	int x;
	Empty e;
};

int main(){
	cout << sizeof(HoldAnInt) << endl; //VS 2013上输出8

	system("pause");
	return 0;
}

上述例子中sizeof(HoldAnInt)>sizeof(int),VS 2013中sizeof(Empty)的值是1,因为对于”大小为零之独立对象“,通常C++会安插一个char到空对象内。

#include<iostream>
using namespace std;

class Empty{};
class HoldAnInt:private Empty{
private:
	int x;
};

int main(){
	cout << sizeof(HoldAnInt) << endl; //VS 2013上输出4

	system("pause");
	return 0;
}

上述例子中sizeof(HoldAnInt)==sizeof(int),这是所谓的EBO(empty base optimization;空白基类最优化),EBO一般只在单一继承下才可行。

请记住:

  • Private继承意味着is-implemented-in-terms-of(根据某物实现出)。它通常比复合(composition)的级别低。当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。
  • 和复合(compoistion)不同,private继承可以造成empty base最优化。这对致力于"对象尺寸最小化"的程序库开发者而言,可能很重要。

条款40:明智而审慎地使用多重继承

1、多重继承往往会导致较多的歧异机会

#include<iostream>
using namespace std;

class BorrowableItem{
public:
	void checkOut(){
		cout << "BorrowableItem::checkout" << endl;
	}
};
class ElectronicGadget{
private:
	bool checkOut() const{
		cout << "ElectronicGadget::checkout" << endl;
	}
};
class MP3Player:public BorrowableItem,public ElectronicGadget{};

int main(){
	MP3Player mp;
	//mp.checkOut();//调用歧异
	mp.BorrowableItem::checkOut();

	system("pause");
	return 0;
}

上述例子中,BorrowableItem类和ElectronicGadget类都有checkOut函数,MP3Player类同时继承BorrowableItem和ElectronicGadget的checkOut函数,所以在调用的时候无法确定调用哪个。虽然BorrowableItem内的checkOut是public,ElectronicGadget内的checkOut是private,但是在看到是否有个函数可取用之前,C++首先确认这个函数对此调用之言是最佳匹配。而上述例子中两个类的checkOut函数匹配程度相同,所以才会造成歧异。解决这个歧异的方法是明白指出要调用哪一个基类内的函数。

2、“钻石型多重继承”也是多重继承会产生的一种情况。

基类的成员会经每一条路径被复制,最终的继承类中会有多笔基类的成员。解决这个问题的方法是让那个基类成为虚基类,即让继承它的类采用虚继承。例子见http://blog.csdn.net/ruan875417/article/details/46408475这篇文章的三、重复多重继承(带成员变量、虚函数、虚函数覆盖)和五、钻石型的虚拟多重继承(带成员变量、虚函数、虚函数覆盖)。

使用虚继承的那些类所产生的对象往往比使用非虚继承的类产生的对象体积大,访问虚基类的成员变量时,也比访问非虚基类的成员变量速度慢。虚基类的成本还包括其他方面。虚基类初始化的规则比非虚基类的情况复杂且不直观。虚基类的初始化责任是由继承体系中的最低层(most derived)class负责,这暗示a、class若派生自虚基类而需要初始化,必须认知其虚基类——不论那些基类距离多远,b、当一个新的继承类加入继承体系中,它必须承担其虚基类的初始化责任。

3、多重继承也有它的合理用途。它的一个通情达理的应用是将“public继承自某接口”和“private继承自某实现”结合在一起。

class Iperson {
public:
	virtual ~IPerson();
	virtual std::string name() const = 0;
	virtual std::string birthDate() const = 0;
};

class DatabaseID { ... };    //稍后被使用

class PersonInfo {           //这个class有若干有用函数,可用以实现IPerson接口
	explicit PersonInfo(DatabaseID pid);
	virtual ~PersonInfo();
	virtual const char* theName() const;
	virtual const char* theBirthDate() const;
	virtual const char* valueDelimOpen() const;
	virtual const char* valueDelimClose() const;
};

class CPerson : public Iperson, private PersonInfo {     //注意,多重继承
public:
	explicit Cperson(DatabaseID pid) : PersonInfo(pid) {}
	virtual std::string name() const {        //实现必要的IPerson成员函数
		return PersonInfo::theName();
	}
	virtual std::string birthDate() const {     //实现必要的IPerson成员函数
		return PersonInfo::theBirthDate();
	}
private:
	const char* valueDelimOpen() const {       //重新定义继承而来的virtual“界限函数”
		return "";
	}
	const char* valueDelimClose() const {
		return "";
	}
};

请记住:

  • 多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要。
  • virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes不带任何数据,将是最具实用价值的情况。
  • 多重继承的确有正当用途。其中一个情节涉及“public继承某个Interface class”和“private继承某个协助实现的class”的两相组合。

### 关于ArcGIS License Server无法启动的解决方案 当遇到ArcGIS License Server无法启动的情况,可以从以下几个方面排查并解决问题: #### 1. **检查网络配置** 确保License Server所在的计算机能够被其他客户端正常访问。如果是在局域网环境中部署了ArcGIS Server Local,则需要确认该环境下的网络设置是否允许远程连接AO组件[^1]。 #### 2. **验证服务状态** 检查ArcGIS Server Object Manager (SOM) 的运行情况。通常情况下,在Host SOM机器上需将此服务更改为由本地系统账户登录,并重启相关服务来恢复其正常工作流程[^2]。 #### 3. **审查日志文件** 查看ArcGIS License Manager的日志记录,寻找任何可能指示错误原因的信息。这些日志可以帮助识别具体是什么阻止了许可服务器的成功初始化。 #### 4. **权限问题** 确认用于启动ArcGIS License Server的服务账号具有足够的权限执行所需操作。这包括但不限于读取/写入特定目录的权利以及与其他必要进程通信的能力。 #### 5. **软件版本兼容性** 保证所使用的ArcGIS产品及其依赖项之间存在良好的版本匹配度。不一致可能会导致意外行为完全失败激活license server的功能。 #### 示例代码片段:修改服务登录身份 以下是更改Windows服务登录凭据的一个简单PowerShell脚本例子: ```powershell $serviceName = "ArcGISServerObjectManager" $newUsername = ".\LocalSystemUser" # 替换为实际用户名 $newPassword = ConvertTo-SecureString "" -AsPlainText -Force Set-Service -Name $serviceName -StartupType Automatic New-ServiceCredential -ServiceName $serviceName -Account $newUsername -Password $newPassword Restart-Service -Name $serviceName ``` 上述脚本仅作为示范用途,请依据实际情况调整参数值后再实施。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值