文档章节

Effective C++: public继承(is-a).

SHIHUAMarryMe
 SHIHUAMarryMe
发布于 2016/03/26 14:24
字数 1006
阅读 41
收藏 0

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

何为(is-a)?

也就是能执行在Base-class(基类)身上的操作,都能执行在Derived-class身上,但是能执行在Derived-class身上的操作并不一定能执行在Base-class上面.

 case 1: 在抽象基类中声明并且实现纯函数,派生类中不再实现,此时无论是派生类还是基类都不能作为对象,否则就会报错.

#include <iostream>

class Base {
public:
	Base() = default;
	Base(const int& val) :value(val) {}
	Base(const Base& other) :value(other.value) {}
	Base(Base&& other) :value(other.value) {}
	
	Base& operator=(const Base& other)
	{
		this->value = other.value;
		return *this;
	}

	Base& operator=(Base&& other)
	{
		this->value = other.value;
		return *this;
	}

	virtual ~Base() = default; //注意这里作为基类的情况下必须把构造函数作为虚函数.
	                                         //在析构函数调用的时候就能保证析构正确的内容.

	virtual void print()const  //virtual function
	{
		std::cout << this->value << std::endl;
	}

	void word(const int& number)const //!
	{
		std::cout << number << std::endl;
	}

private:
	int value{ 10 }; //在调用默认构造函数的情况下会调用这里的初始化语句.
};

class PureBase { //由于有 pure virtual function因此该class并不能当对象使用.
public:
	virtual ~PureBase() = default;
	virtual void pureVirFunc()const = 0; //pure virtual function!

protected: //注意我们都定义为了: protected
	             //因为由于含有pure virtual function, 因此我们不能使用PureBase,把下面的函数都定义为protected的更加合适.
	PureBase() = default;
	PureBase(const int& num) :number(num),theNum(num+10) {}

	//PureBase(const PureBase& other) :number(other.number), theNum(other.theNum){}
	//PureBase(PureBase&& other) :number(other.number), theNum(other.theNum) {}
	//const PureBase& operator=(const PureBase& other)
	//{
	//	this->number = other.number;
	//	this->theNum = other.theNum;
	//	return *this;
	//}
	//const PureBase& operator=(PureBase&& other)
	//{
	//	this->number = std::move(other.number);
	//	this->theNum = std::move(other.theNum);
	//	return *this;
	//}

	const int& getPrivateData()const
	{                                                     
		return (this->theNum);
	}

	int& getPrivateData()
	{
		return (this->number);
	}

	template<typename T>
	void setData(T&& number)
	{
		this->theNum = std::forward<T>(number);
	}

	int number{ 20 }; //注意数据这里也是: protected的.
	                           //为了给派生类可见,而且确保派生类能够修改派生来的数据. 

private:
	int theNum{ 30 };
};

void PureBase::pureVirFunc()const //注意这里我们给上面的 pure virtual function 提供了定义.
{                                                      //为什么要提供定义呢! 因为需要访问PureBase的private的成员.
	std::cout << "pureVirtualFunction In PureBase: " << this->theNum << std::endl;
}





class DerivedOne : public Base, public PureBase {
public:
	DerivedOne() = default;
	DerivedOne(const int& v) : Base(v), PureBase(v), data(v) {}//注意这里我们使用了: 基类中的protected的构造函数.
	virtual ~DerivedOne() = default;

	DerivedOne(const DerivedOne& other)
		:Base(other),
		data(other.data)
	{
		this->number = other.number;
		this->setData(other.getPrivateData());
		//PureBase::PureBase(other); //由于PureBase是个abstract-class因此并不能使用.
	}

	DerivedOne(DerivedOne&& other)
		:Base(other),
		data(other.data)
	{
		this->number = other.number;
		this->setData(std::move(other.getPrivateData()));
	}

	DerivedOne& operator=(const DerivedOne& other)
	{
		Base::operator=(other);
		this->number = other.number;
		this->setData(other.getPrivateData());

		return *this;
	}

	DerivedOne& operator=(DerivedOne&& other)
	{
		Base::operator=(other);
		this->number = std::move(other.number);
		this->setData(std::move(other.getPrivateData()));

		return *this;
	}

	virtual void pureVirFunc()const override
	{
		std::cout << "pureVirtualFunction In Derived Class: " << this->data << std::endl;
	}

	virtual void print()const override
	{
		std::cout << "DerivedOne-class: " << this->number << std::endl;
	}

	void print(const int& theVal, int rightVal)const //注意这里,并不会影响虚函数的动态调用.
	{
		rightVal = 100;
		int x{};
		x = 200;
		std::cout << "theVal: " << theVal << std::endl;
	}

	void word()const  //这里会覆盖继承而来的: 所有同名的函数,不管参数返回类型如何, 只要函数名字一样就会被覆盖.
	{
		std::cout << "therWordInDerivedClass" << std::endl;
	}

private:
	int data{ 40 };
};


int main()
{
	Base base{};
	DerivedOne derived;

	//case 1:  不能创建一个abstract-class作为对象.
	//PureBase pureBase{};

	//case 2:  可以作为动态调用的对象.
	PureBase& pB{ derived };
	pB.pureVirFunc();

	//case 3
	DerivedOne de{ 40 };
	derived = de;

	//case 4: 派生类的同名函数隐藏了,基类中的同名函数,不管返回类型,还有参数如何.
	derived.word();
	//derived.word(20); //error!
	derived.Base::word(20); //但是我们可以强制调用.

	return 0;
}

 

case2: 基类向派生类转换其中 只有派生类中基类部分被初始化了, 派生类自己的部分处于未定义状态.

 #include <iostream>
#include <string>
class Base{
 private:
  int number_;
  
  public:
   explicit Base(const int& n_):number_(n_){}
   
   virtual ~Base()=default;
   
   virtual void print()const
   {
    std::cout<<this->number_<<std::endl;
   }
   
   void set_number()noexcept
   {
    this->number_ = 1;
   }
};
class InheritBase : public Base{
 private:
  std::string str_;
  
  public:
   InheritBase()=default;
   
   InheritBase(const int& number_, const std::string& s_):Base(number_),str_(s_){}
   
   void println()const
   {
    std::cout<<this->str_<<std::endl;
   }
   
   ~InheritBase()=default;
};
int main()
{
 Base* ptr_b = new InheritBase(520, "shihuawoaini");
 ptr_b->set_number();
 ptr_b->print();
 
 Base* ptr_b2 = new Base(100);
 InheritBase* ptr_i = static_cast<InheritBase*>(ptr_b2);
 //ptr_i->println(); //虽然可以运行但是会在运行中出错,因为InheritBase中的部分是未被初始化的.
 ptr_i->print(); 
 
 
 delete ptr_b2;
 delete ptr_b;
 return 0;
}

 

© 著作权归作者所有

SHIHUAMarryMe
粉丝 13
博文 162
码字总数 138435
作品 0
武汉
程序员
私信 提问
C++继承的话题

析构函数 如果一个类想被别人继承,通常析构函数要声明为虚函数,否则,如下代码就会出现未定义情况。 Base* p=new Derived(); delete p; 这句话反过来说,就是如果你不打算让别人派生你的类...

长平狐
2012/08/28
111
0
C#转C++的一点分享

从C#转C++有段时间了,一直想分享点什么,但又不太好意思分享,毕竟自己做C++的时间不太长,最近感觉自己已能胜任现有工作,想分享的想法又强了点,前几天看到这样一篇博客《那些年·我们读过的专业...

爱情经纬线
2014/01/17
4.2K
11
C++ noncopyable类

在muduo中,有一个类,继承了该类的派生类不能被拷贝,只能被移动。涉及拷贝的函数有两个:拷贝构造函数和拷贝复制操作符。将这两个方法声明为不可访问或者删除(=delete),即可达到不可拷贝...

chenBright
09/29
0
0
C++各阶段学习书目

1. 入门 Lippman的《Essential C++》 顾名思义,这本书是很短小精悍的。通过这本书,可以对C++的最常用和重要的特性有全面的了解,并对C++的全貌有一个概念。虽然这远远不够,但就是这样的书...

晨曦之光
2012/04/24
569
1
C++ 接口

C++中有多继承,多继承很好,但是c++多重继承中,派生类继承了所有父类的实现,导致体积膨胀等缺点。C#和java的设计者坚持单继承,所有的类都派生自Object类,他们提供了interface来模仿c++的...

长平狐
2012/08/28
130
0

没有更多内容

加载失败,请刷新页面

加载更多

mars-config 动态配置管理

mars-config 码云地址:https://gitee.com/fashionbrot/mars-config 介绍 spring mvc 、springboot 动态配置系统。http 轮训方式 更新 动态配置 软件架构 软件架构说明 后端使用技术 :sprin...

fashionbrot
25分钟前
9
0
女朋友玩吃鸡手游被开挂老哥骗炮,我见义勇为将骗子绳之以法

大家好,我是乔哥。 晚上10点以后下班后我回到自如出租房里面,开始处理公众号粉丝发来的消息,一条一条处理,突然看到了这么几条消息,吸引了我的眼球: 然后我就和这位女粉丝小红(化名)聊...

gzc426
30分钟前
3
0
两款软件

fadetop保护眼睛软件 Snipaste截图软件

伟大源于勇敢的开始
57分钟前
6
0
06.全局锁和表锁

根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类。 全局锁 全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是flush tables with read lock(FTW...

scgaopan
今天
7
0
图解安装CentOS8

最近正式发布了CentOS8!迫不及待地准备下载了CentOS8镜像,准备体验下,工作繁忙无暇理会。 今天抽空安装体验下~ 可从CentOS官网下载:https://centos.org/download/ 为了快速可以选择从国...

技术训练营
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部