首页 > 编程语言 >【C++】继承(inheritance)

【C++】继承(inheritance)

时间:2024-11-24 15:31:04浏览次数:12  
标签:inheritance 继承 基类 C++ class int 派生类 public

引入

假设我们有一个动物类

class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};

又想写一个狗类,它也有年龄,也会吃,除此之外还有种类

class Dog {
public:
    const char* kind;
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};

我们发现有重复的代码,如果我们写猫类、鸟类等都要再写一遍,这样很麻烦

那么有没有一种方法能提高代码的复用性,不需要再写一遍就能达到同样的效果呢?

我们让Dog继承Animal

#include<iostream>
class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};
class Dog :public Animal {
public:
    const char* kind;
};
int main() {
    Dog dog;
    dog.kind = "柯基";
    dog.age = 3;
    dog.eat();
}

没有写那部分重复代码却也能给age赋值,调用eat()方法

也就是说,Dog继承了Animal,Animal所拥有的age和eat()它也就有了,就像父亲遗传给儿子一样

  • Animal就叫做父类或者基类
  • Dog就叫做子类或者派生类

而且,狗本来就属于动物,我们让其继承动物也是符合思维的

单继承和多继承

class A {
};
class B :public A {//单继承
};
class D {
};
class E {
};
class F :public D, public E {//多继承
};

那么,子类继承父类后,父类的所有内容都能被子类访问吗?

继承方式

我们看到上面的继承有"public",这其实是继承方式

继承方式就是类中的三种访问属性,每种访问属性通过继承方式之后在派生类中可能会有新的属性

  1. 基类私有成员,不管用什么方式继承,都不能被访问
  2. 其他的成员访问属性和继承方式,两者看谁更严格就按严格的来:public<protected<private
基类成员的访问控制public继承protected继承private继承
private可以继承,但不可以访问可以继承,但不可以访问可以继承,但不可以访问
protectedprotectedprotectedprivate
publicpublicprotectedprivate

派生类的构成

  1. 派生类会继承除基类的构造析构函数之外的所有成员变量和成员函数
  2. 可以在派生类中添加新的成员,通过派生类对象来调用
  3. 如果派生类中添加的成员名和基类成员名相同,那么派生类会隐藏基类的成员,可以通过.基类名::基类成员名来访问。如果是继承的多个基类,而多个基类中也有同名的,也是通过此种方式调用同名的成员。子类对象直接访问同名成员,访问的是子类对象自己的同名成员。

示例:

#include<iostream>
class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};
class Dog :public Animal {
public:
    const char* kind;
    void eat() {
        std::cout << "啃骨头!" << std::endl;
    }
};
int main() {
    Dog dog;
    dog.eat();
    dog.Animal::eat();
}

派生类和基类的关系

子类不包含父类,而是子类中有父类的所有数据成员和函数成员(除构造析构)。派生类是基类对象,但是基类不是派生类对象;派生类可以赋值给基类,而基类不能给派生类赋值。

派生类的构造析构顺序

  1. 派生类对象在实例化的时候是会调用基类的构造函数的,先基类后派生类(先有父亲后有儿子),释放就是先儿子后父亲,因为栈结构(先进后出)
  2. 如果是多继承,其与单继承中构造顺序一致;区别在于,在构造基类时有多个基类,那么会按照基类的继承声明顺序来依次调用基类的构造函数,然后构造子对象,最后构造自己
  3. 在写继承的时候,要确保基类有可以调用的构造函数
  4. 带参构造:在构造过程中,如果基类或子对象需要参数来进行构造,就需要通过成员初始化列表来构造

示例1:

#include<iostream>
class A {
public:
	A() {
		std::cout << "调用A的无参构造" << std::endl;
	}
	A(int a) {
		std::cout << "调用A的有参构造" << std::endl;
	}
	~A() {
		std::cout << "调用A的析构" << std::endl;
	}
};
class B :public A {
public:
	B() {
		std::cout << "调用B的无参构造" << std::endl;
	}
	B(int b) {
		std::cout << "调用B的有参构造" << std::endl;
	}
	~B() {
		std::cout << "调用B的析构" << std::endl;
	}
};
int main() {
	B b1;
	B b2(5);
}

运行结果:

调用A的无参构造
调用B的无参构造
调用A的无参构造
调用B的有参构造
调用B的析构
调用A的析构
调用B的析构
调用A的析构

示例2:

#include<iostream>
class A {
public:
	A(int a) {
		std::cout << a << std::endl;
	}
};
class B :public A {
public:
	B():A(1){}//在初始化列表中调用父类的带参构造
	//不这样写直接实例化会报错
};
int main() {
	B b1;
}

派生类的内存大小

  • 派生类的内存大小=所有父类内存大小之和+本身新增的成员内存大小
  • 派生类的内存中,基类的内存在最低位,派生类的内存在最高位

菱形继承

菱形继承

类B,C分别继承A;类D继承类B,C

这样继承会导致类D继承两份类A的成员,在类D对象,想要访问类A的成员的时候,会导致访问不明确。因为类B,C各自继承类A的成员

解决方法

(1)通过类名::成员名来确定调用哪个成员(不常用)

(2)通过虚继承,在继承方式的前面加上关键字virtual,虚继承之后会使在虚继承的类中多个指针(内存就会变大),但是在最后的D类,不会再继承两份A的成员了

示例1:

#include<iostream>
class A {
	int a = 1;
};
class B :public A {
	int c = 2;
};
class C :public A {
	int d = 3;
};
class D :public B, public C {
	int e = 4;
};
int main() {
	std::cout << sizeof(A) << std::endl;//4
	std::cout << sizeof(B) << std::endl;//8
	std::cout << sizeof(C) << std::endl;//8
	std::cout << sizeof(D) << std::endl;//20
}

示例2:

#include<iostream>
class A {
	int a = 1;
};
class B :virtual public A {
	int c = 2;
};
class C :virtual public A {
	int d = 3;
};
class D :public B, public C {
	int e = 4;
};
int main() {
	std::cout << sizeof(A) << std::endl;//32位:4	64位:4
	std::cout << sizeof(B) << std::endl;//32位:12	64位:24
	std::cout << sizeof(C) << std::endl;//32位:12	64位:24
	std::cout << sizeof(D) << std::endl;//32位:24	64位:48
}

标签:inheritance,继承,基类,C++,class,int,派生类,public
From: https://blog.csdn.net/qq_45951891/article/details/144001052

相关文章

  • 实验4 类的组合、继承、模板类、标准库
    1.实验任务1task1_1.cpp:#include<iostream>usingstd::cout;usingstd::endl;//类A的定义classA{public:A(intx0,inty0);voiddisplay()const;private:intx,y;};A::A(intx0,inty0):x{x0},y{y0}{}voidA::display()const{......
  • 【C++】类(一):定义抽象数据类型
    类这部分内容对应于C++Primer第五版的第七章全部内容。原书当中的内容包括:7.1定义抽象数据类型;7.2访问控制与封装;7.3类的其它特性;7.4类的作用域;7.5构造函数再探;7.6类的静态成员;类的基本思想是数据抽象(dataabstraction)和封装(encapsulation)。数据抽象是一种依赖......
  • 实验四 c++
    任务一:task1_1.cpp:#include<iostream>usingstd::cout;usingstd::endl;//类A的定义classA{public:A(intx0,inty0);voiddisplay()const;private:intx,y;};A::A(intx0,inty0):x{x0},y{y0}{}voidA::display()const{......
  • 【C++】list容器及其模拟实现
    目录1.list的介绍及使用1.1list的介绍1.2list的使用1.2.1list的构造1.2.2listiterator的使用1.2.3listcapacity1.2.4listelementaccess1.2.5listmodifiers1.2.6list的迭代器失效2.list的模拟实现2.1模拟实现list2.1.1list节点2.1.2list常见功能......
  • SpringCloudAlibaba系列---【maven如何实现多继承?】
    1.问题当我们使用SpringCloudAlibaba创建微服务的时候,我们的父pom工程的parent肯定是springboot-parent,但是,我们又要使用spring-cloud-alibaba-dependencies作为版本管理,parent肯定只能有一个,这时候该怎么办呢?2.解决方案使用dependencyManagement的pom和import即可,例如下面的sp......
  • python VS c++
    一、语法特点Python:语法简洁、优雅,代码可读性极强,采用缩进来表示代码块,摒弃了像C++那样使用大括号的传统方式,使得代码看上去十分清晰简洁。例如:​if5>3:print("5大于3")elif5==3:print("5等于3")else:print("5小于3")​整个代码结构通过......
  • 实验4 类的组合、继承、模板类、标准库
    一、实验目的知道什么是类模板,会正确定义和使用简单的类模板会使用C++正确定义、使用派生类加深对类的组合机制(has-a)、类的继承机制(is-a)的领悟和理解练习标准库string,vector用法,能基于问题场景灵活使用针对具体问题场景,练习运用面向对象思维进行设计......
  • 实验4 类的组成、继承、模板类、标准库
    任务二:代码:task2.cpp:1#include"GradeCalc.hpp"2#include<iomanip>34voidtest(){5intn;6cout<<"输入班级人数:";7cin>>n;89GradeCalcc1("OOP",n);1011cout<&......
  • 实验4 类的组合、继承、模板类、标准库
    实验任务2:task2.cpp源码:1#include"GradeCalc.hpp"2#include<iomanip>34voidtest(){5intn;6cout<<"输入班级人数:";7cin>>n;89GradeCalcc1("OOP",n);1011cout<&......
  • C++-练习-99
    题目:编写一个程序计算流中第一个$之前的字符数目,并将$留在输入流中源代码:#include<iostream>intmain(){charinput;intcount=0;std::cout<<"Enteraphase:";while(std::cin.peek()!='$'){......