首页 > 编程语言 >c++的继承

c++的继承

时间:2024-07-19 21:57:06浏览次数:15  
标签:name 继承 子类 成员 c++ human 父类

目录

一、什么是继承

二、继承的格式

三、子类和父类

一、子类对父类的赋值

二、子类与父类的同名成员变量

 三、子类和父类的同名成员函数

四、子类的默认成员函数

一、构造函数

二、析构函数

三、拷贝构造

四、赋值运算符重载


一、什么是继承


定义:

继承(inheritance)机制是面向对象程序设计中使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生的新类,称派生类(或子类),被继承的类称基类(或父类)。

继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。之前接触的复用都是函数复用,继承是类设计层次的复用。

二、继承的格式

class 新类的名字:继承方式 继承类的名字{};

新类就是继承的类,称为子类或派生类,被继承的类被称为父类或基类。

继承的权限:

继承的总结:
1.基类private成员无论以什么方式继承到派生类中都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。
2.基类private成员在派生类中不能被访问,如果基类成员不想在派生类外直接被访问,但需要在派生类中访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
3.基类的私有成员在子类都是不可见;基类的其他成员在子类的访问方式就是访问限定符和继承方式中权限更小的那个(权限排序:public>protected>private)。
4.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,但最好显式地写出继承方式。

三、子类和父类

一、子类对父类的赋值

子类可以直接对父类进行赋值,因为父类有的子类都有,赋值的也只是父类的那一部分。

子类对父类的赋值有三种方式

直接赋值:

student st;//子类
    human hm;//父类
    hm = st;

 引用赋值:

student st;//子类
    human& hm=st;父类

指针赋值:

student st;//子类
    human* hm=&st;//父类

二、子类与父类的同名成员变量

 如果在子类与父类中出现了同名的成员变量,父类的成员变量会被隐藏,默认使用子类的成员变量,如果想要使用父类的成员变量,需要用父类名直接修饰限定。

void print()
    {
        cout << human::name << endl;
    }

 三、子类和父类的同名成员函数

class human {
public:
    string name = "小明";
    void print()
    {
        cout << name << endl;
    }
};
class student :public human {
public:
    string name = "小红";
    void print()
    {
        cout << name << endl;
    }
};
int main()
{
    student st;
    st.print();
    return 0;
}

可以看到父类和子类有同名的成员函数,这时候去运行,调用的只会是子类的成员函数。 

如果想要调用父类的成员函数也要和成员变量一样,加上修饰符限定。

四、子类的默认成员函数

一、构造函数

编译器会默认先调用父类的构造函数,再调用子类的构造函数

class human {
public:
	human(string name = "小明")//先调用:父类默认构造调用一个print打印name
		:_name(name)
	{
		cout << name << endl;
	}
protected:
	string _name;
};
 
 
class student :public human {//后调用:子类默认构造调用一个print打印name和age
public:
	student(string name,int age)
		:_age(age)
	{
		cout << name << endl<<age<<endl;
	}
protected:
	int _age;
};
 
 
int main()
{
	student st("小红", 18);
	return 0;
}

子类的构造函数会在初始化列表开始时调用父类的默认构造,也可以自己显示调用父类的构造函数。

二、析构函数

class human {
public:
	human(string name = "小明")
		:_name(name)
	{}
	~human()
	{
		cout << "我是父类" << endl;
	}
protected:
	string _name;
};
class student :public human {
public:
	student(string name,int a = 20)
		:age(a)
	{}
	~student()
		
	{
		cout <<"我是子类"<< endl;
	}
protected:
	int age;
};
int main()
{
	student st("小明", 18);
	return 0;
}

子类的析构函数会自动执行父类的析构函数,不管有没有显示调用,因为编译器奉行,先析构子类,再析构父类,以防止一些不必要的bug。

三、拷贝构造

class human {
public:
	human(string name="小明")
		:_name(name)
	{
		cout << name << endl;
	}
protected:
	string _name;
};
class student:public human {
public:
	student(string name, int age)
		:_age(age)
	{
		cout << name << endl << age << endl;
	}
	student(student& s)
		:human(s)//直接将st传过来通过切片拿到父类中的值
		,_age(s._age)//拿除了父类之外的值
	{
		cout << s._age << endl<<s._name<<endl;
	}
protected:
	int _age;
};
int main()
{
	student st("小红",18);
	student st2(st);
	return 0;
}

子类中调用父类的拷贝构造时,直接传入子类对象即可,父类的拷贝构造会通过“切片”拿到父类的那一部分。

四、赋值运算符重载

class human {
public:
	human(string name = "小明")
		:_name(name)
	{
	}
	human& operator=(const human& p)
	{
		if (this != &p)
		{
			cout << "调用父类" << endl;
			_name = p._name;
		}
		return *this;
	}
protected:
	string _name;
};
class student :public human {
public:
	student(string name, int age)
		:_age(age)
	{
	}
	student(student& s)
		:human(s)
		, _age(s._age)
	{
	}
	student& operator=(const student& s)
	{
		if (this != &s)
		{
			cout << "调用了子类" << endl;
			human::operator=(s);//必须调用父类运算符
			_age = s._age;
			_name = s._name;
		}
		return *this;
	}
protected:
	int _age;
};
int main()
{
	student st("小红", 18);
	student st2(st);
	student st3("小刚", 16);
	st = st3;
	return 0;
}

子类的operator=必须要显式调用父类的operator=完成父类的赋值。

因为子类和父类的运算符,编译器默认给与了同一个名字,所以构成了隐藏,所以每次调用=这个赋值运算符都会一直调用子类,会造成循环,所以这里的赋值要直接修饰限定父类。

标签:name,继承,子类,成员,c++,human,父类
From: https://blog.csdn.net/2401_82609762/article/details/140557947

相关文章

  • C++类和对象(二)
    目录默认成员函数一、构造函数二、析构函数三、拷贝构造函数四、赋值运算符重载五、取地址运算符重载六、const成员函数七、日期类实现默认成员函数默认成员函数就是用户没有显式实现,编译器会自动⽣成的成员函数称为默认成员函数。⼀个类,我们不写的情况下编译器会默......
  • 线程池(C++11)
    已经有现成的实现,本博客摘抄讲解附源码链接。参考的博客质量已经非常高,避免找来找去。1、避免频繁创建、销毁线程,实现复用。思路如下:2、线程函数多种多样,如何封装成统一的函数类型void()第一次封装我们使用bind()函数将多个参数的函数封装为没有形参的package_task对象,因为p......
  • 奇妙的 c++ 混合运算式
    先来看看如下的式子:a*b+c当你在c++中运行它时,你很清楚它是先计算*再计算+的。那么请再来看看这个式子:a+b+c请问它是先执行第一个+,还是先执行第二个+呢?这个问题看上去无解,但实际上我们可以解答:#definelllonglonginta=INT_MAX,b=INT_MAX;llc......
  • C++类和对象 后篇
    C++类和对象后篇构造函数的初始化列表......
  • c++一句话求前缀和,不用循环
    partial_sum是C++标准库中的一个函数,用于计算给定范围内元素的部分和。它接受三个参数:起始迭代器(包含在计算范围内的第一个元素)结束迭代器(不包含在计算范围内的最后一个元素)输出迭代器(存储部分和结果的起始位置)在这个例子中,a.begin()+1表示从数组a的第二个元素开始计......
  • C++ 定义静态数据成员简单测试
    #include<iostream>#include<string>namespace{classA{public:voidaddCount(){++sumCount;}staticintgetSumCount(){returnsumCount;}private:......
  • Facebook 开源 C++ 框架 Ocean:用于计算机视觉和增强现实
    Facebook开源C++框架Ocean:用于计算机视觉和增强现实来源:OSCHINA编辑: 局2024-07-1211:05:00 0Facebook开源了其内部用于计算机视觉(CV)和增强现实(AR) 应用程序的框架Ocean,用于执行各种任务,包括计算机视觉、几何、媒体处理、网络和渲染。Ocean......
  • C++多线程
    多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程。基于进程的多任务处理是程序的并发执行。基于线程的多任务处理是同一程序的片段的并发执行。多线程程序包含可以同时运行的两个或多个......
  • C++宏魔法:__VA_OPT__操作
    在阅读chromium源码的时候,在\blinkrendercore的base\check.h头文件中,发现了这个定义:#defineCHECK(condition,...)\LOGGING_CHECK_FUNCTION_IMPL(\::logging::C......
  • C++ 智能指针
    一、为什么需要智能指针看如下代码有什么问题:intdiv(){ inta,b; cin>>a>>b; if(b==0) throwinvalid_argument("除0错误"); returna/b;}voidFunc(){ //1、如果p1这里new抛异常会如何? //2、如果p2这里new抛异常会如何? //3、如果div调用这里又......