Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C++】继承

【C++】继承

作者头像
用户11375356
发布于 2024-11-22 12:52:45
发布于 2024-11-22 12:52:45
14400
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

1. 继承的概念及定义

1.1 继承的概念

继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。继承 呈现了⾯向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复⽤,继承是类设计层次的复⽤。

下⾯我们看到没有继承之前我们设计了两个类Student和Teacher,Student和Teacher都有姓名/地址/ 电话/年龄等成员变量,都有identity⾝份认证的成员函数,设计到两个类⾥⾯就是冗余的。当然他们也有⼀些不同的成员变量和函数,⽐如⽼师独有成员变量是职称,学⽣的独有成员变量是学号;学⽣ 的独有成员函数是学习,⽼师的独有成员函数是授课。

class Person { public:     //进入校园/图书馆/实验室二维码等身份证认证     void identity()     {         cout << "void identity()" << _name << endl;         cout << _age << endl;     } protected:         string _name = "张三"; // 姓名         string _address; // 地址         string _tel; // 电话 private:         int _age = 18; // 年龄 }; class Student :public Person { public:     //学习     void study()     {         identity();          // ...     } protected:     int _stuid;//学号 }; class Teacher : public Person { public:     // 授课     void teaching()     {         //...     } protected:     string title; // 职称 }; int main() {     Student s;     Teacher t;     s.identity();     t.identity();     return 0; }

下⾯我们公共的成员都放到Person类中,Student和teacher都继承Person,就可以复⽤这些成员,就不需要重复定义了,省去了很多⿇烦。

class Person { public:     //进入校园/图书馆/实验室二维码等身份证认证     void identity()     {         cout << "void identity()" << _name << endl;         cout << _age << endl;     } protected:         string _name = "张三"; // 姓名         string _address; // 地址         string _tel; // 电话 private:         int _age = 18; // 年龄 }; class Student :public Person { public:     //学习     void study()     {         identity();          // ...     } protected:     int _stuid;//学号 }; class Teacher : public Person { public:     // 授课     void teaching()     {         //...     } protected:     string title; // 职称 }; int main() {     Student s;     Teacher t;     s.identity();     t.identity();     return 0;  }

1.2 继承定义

1.2.1 定义格式

下⾯我们看到Person是基类,也称作⽗类。Student是派⽣类,也称作⼦类。(因为翻译的原因,所以既叫基类/派⽣类,也叫⽗类/⼦类)

1.2.2 继承基类成员访问⽅式的变化

1. 基类private成员在派⽣类中⽆论以什么⽅式继承都是不可⻅的。这⾥的不可⻅是指基类的私有成员 还是被继承到了派⽣类对象中,但是语法上限制派⽣类对象不管在类⾥⾯还是类外⾯都不能去访问 它。

2. 基类private成员在派⽣类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派⽣类 中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。

3. 实际上⾯的表格我们进⾏⼀下总结会发现,基类的私有成员在派⽣类都是不可⻅。基类的其他成员 在派⽣类的访问⽅式 == Min(成员在基类的访问限定符,继承⽅式),public > protected > private。

4. 使⽤关键字class时默认的继承⽅式是private,使⽤struct时默认的继承⽅式是public,不过最好显 ⽰的写出继承⽅式。

5. 在实际运⽤中⼀般使⽤都是public继承,⼏乎很少使⽤protetced/private继承,也不提倡使⽤ protetced/private继承,因为protetced/private继承下来的成员都只能在派⽣类的类⾥⾯使⽤,实 际中扩展维护性不强。

// 实例演⽰三种继承关系下基类成员的各类型成员访问关系的变化 class Person { public:     void Print()     {         cout << _name << endl;     } protected:     string _name; // 姓名 private:     int _age; // 年龄 }; //在保护继承中,基类的所有公有成员和保护成员在派生类中都将变成保护成员,而基类的私有成员在派生类中仍然不可访问 //class Student : protected Person //在私有继承中,基类的所有公有成员和保护成员在派生类中都将变成私有成员,而基类的私有成员在派生类中仍然不可访问。 //class Student : private Person //在公有继承中,基类的公有成员和保护成员在派生类中保持其原有的访问权限,而基类的私有成员在派生类中仍然不可访问。 class Student : public Person { protected:     int _stunum; // 学号 };

1.3 继承类模板

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
namespace xc
{
	//template<class T>
	//class vector
	//{};
	template<class T>
	class stack :public std::vector<T>
	{
	public:
		void push(const T& x)
		{
            // 基类是类模板时,需要指定⼀下类域,
            // 否则编译报错:error C3861: “push_back”: 找不到标识符
            // 因为stack<int>实例化时,也实例化vector<int>了
            // 但是模版是按需实例化,push_back等成员函数未实例化,所以找不到
         
			vector<T>::push_back(x);
            //push_back(x);

		}
		void pop()
		{
			vector<T>::pop_back();
		}
			
		const T& top()
		{
			return vector<T>::back();
		}
			
		bool empty()
		{
			return vector<T>::empty();
		}
	};

}
int main()
{
	xc::stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}

	return 0;
}
			vector<T>::push_back(x);
            
		}
		void pop()
		{
			vector<T>::pop_back();
		}
			
		const T& top()
		{
			return vector<T>::back();
		}
			
		bool empty()
		{
			return vector<T>::empty();
		}
	};

}
int main()
{
	xc::stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}

	return 0;
}

运行结果: 

2. 基类和派⽣类间的转换

public继承的派⽣类对象可以赋值给基类的指针 / 基类的引⽤。这⾥有个形象的说法叫切⽚或者切割。寓意把派⽣类中基类那部分切出来,基类指针或引⽤指向的是派⽣类中切出来的基类那部分。

基类对象不能赋值给派⽣类对象。

基类的指针或者引⽤可以通过强制类型转换赋值给派⽣类的指针或者引⽤。但是必须是基类的指针 是指向派⽣类对象时才是安全的。这⾥基类如果是多态类型,可以使⽤RTTI(Run-Time Type Information)的dynamic_cast 来进⾏识别后进⾏安全转换。(ps:这个我们后⾯类型转换章节再 单独专⻔讲解,这⾥先提⼀下)

class Person { protected:     string _name; // 姓名     string _sex; // 性别     int _age; // 年龄 }; class Student : public Person { public:     int _No; // 学号 }; int main() {     Student sobj;     // 1.派⽣类对象可以赋值给基类的指针/引⽤     Person* pp = &sobj;     Person& rp = sobj;     // 派⽣类对象可以赋值给基类的对象是通过调⽤后⾯会讲解的基类的拷⻉构造完成的     Person pobj = sobj;     //2.基类对象不能赋值给派⽣类对象,这⾥会编译报错     //sobj = pobj;     return 0; }

3. 继承中的作用域

3.1 隐藏规则:

1. 在继承体系中基类和派⽣类都有独⽴的作⽤域。

2. 派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏。 (在派⽣类成员函数中,可以使⽤ 基类::基类成员 显⽰访问)

3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

4. 注意在实际中在继承体系⾥⾯最好不要定义同名的成员。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是⾮常容易混淆
class Person
{
protected:
	string _name = "小李子"; // 姓名
	int _num = 111; // ⾝份证号
};
class Student : public Person
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 身份证号:" << Person::_num << endl;
		cout << " 学号:" << _num << endl;
	}
protected:
	int _num = 999; // 学号
};
int main()
{
	Student s1;
	s1.Print();
	return 0;
};

运行结果: 

3.2 考察继承作⽤域相关选择题

1. A和B类中的两个func构成什么关系(B

A. 重载         B. 隐藏         C.没关系

2.下⾯程序的编译运⾏结果是什么(A

A. 编译报错         B. 运⾏报错         C. 正常运⾏

class A { public:     void fun()     {         cout << "func()" << endl;     } }; class B : public A { public:     void fun(int i)     {         cout << "func(int i)" << i << endl;     } }; int main() {     B b;     b.fun(10);     //b.fun();  //只需要函数名相同就构成隐藏,基类被隐藏了所以调用不过去     b.A::fun();//这样就可以了     return 0; };

4. 派生类的默认成员函数

4.1 四个常见默认成员函数

6个默认成员函数,默认的意思就是指我们不写,编译器会变我们⾃动⽣成⼀个,那么在派⽣类中,这⼏个成员函数是如何⽣成的呢?

1. 派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。如果基类没有默认的构造函数,则必须在派⽣类构造函数的初始化列表阶段显⽰调⽤。

2. 派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化。

3. 派⽣类的operator=必须要调⽤基类的operator=完成基类的复制。需要注意的是派⽣类的operator=隐藏了基类的operator=,所以显⽰调⽤基类的operator=,需要指定基类作⽤域

4. 派⽣类的析构函数会在被调⽤完成后⾃动调⽤基类的析构函数清理基类成员。因为这样才能保证派⽣类对象先清理派⽣类成员再清理基类成员的顺序。

5. 派⽣类对象初始化先调⽤基类构造再调派⽣类构造。

6. 派⽣类对象析构清理先调⽤派⽣类析构再调基类的析构。

7. 因为多态中⼀些场景析构函数需要构成重写,重写的条件之⼀是函数名相同(这个我们多态章节会讲解)。那么编译器会对析构函数名进⾏特殊处理,处理成destructor(),所以基类析构函数不加 virtual的情况下,派⽣类析构函数和基类析构函数构成隐藏关系。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person
{
public:
	Person(const char* name = "xxx")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;
		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name;//姓名
};
class Student : public Person
{
public:
	Student(const char* name, int num, const char* addrss)
		: Person(name)
		, _num(num)
		, _addrss(addrss)
	{}
	// 严格说Student拷贝构造默认生成的就够用了
	// 如果有需要深拷贝的资源,才需要自己实现
	Student(const Student& s)
		: Person(s)
		, _num(s._num)
		, _addrss(s._addrss)
	{
		//深拷贝
	}
	// 严格说Student赋值重载默认生成的就够用了
	// 如果有需要深拷贝的资源,才需要自己实现
	Student operator=(const Student& s)
	{
		if (this != &s)
		{
			//父类和子类的operator=构成隐藏关系
			Person::operator=(s);
			_num = s._num;
			_addrss = s._addrss;
		}
		return *this;
	}
	// 严格说Student析构默认生成的就够用了
	// 如果有需要显示释放的资源,才需要自己实现
	// 析构函数都会被特殊处理成destructor() 
	~Student()
	{
		// 子类的析构和父类析构函数也构成隐藏关系
		// 规定:不需要显示调用,子类析构函数之后,会自动调用父类析构
		// 这样保证析构顺序,先子后父,显示调用取决于实现的人,不能保证
		// 先子后父
		//Person::~Person();
		//delete _ptr;
	}
protected:
	int _num = 1;//学号
	string _addrss = "湖南省长沙市";

	int* _ptr = new int[10];
};
int main()
{
	Student s1("张三", 1, "湖南省");
	Student s2(s1);

	Student s3("李四", 1, "广东省");
	s1 = s3;
	
	return 0;
}

运行结果:

4.2 实现⼀个不能被继承的类

⽅法1:基类的构造函数私有,派⽣类的构成必须调⽤基类的构造函数,但是基类的构成函数私有化以后,派⽣类看不⻅就不能调⽤了,那么派⽣类就⽆法实例化出对象。

⽅法2:C++11新增了⼀个final关键字,final修改基类,派⽣类就不能继承了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// C++11的⽅法
class Base final
{
public:
	void func5() { cout << "Base::func5" << endl; }
protected:
	int a = 1;
private:
	// C++98的⽅法
	/*Base()
	{}*/
};
//error C3246: "Derive": 无法从 "Base" 继承,因为它已声明为 "final"
class Derive :public Base
{
	void func4() { cout << "Derive::func4" << endl; }
protected:
	int b = 2;
};
int main()
{
	Base b;
	Derive d;
	return 0;
}

5. 继承与友元

友元关系不能继承,也就是说基类友元不能访问派⽣类私有和保护成员。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//前置声明
class Student;

class Person
{
public:
	// 友元关系不能被继承
	friend void Display(const Person& p, const Student& s);
protected:
	string _name; // 姓名
};

class Student : public Person
{
	//这样就可以了
	friend void Display(const Person& p, const Student& s);
protected:
	int _stuNum; // 学号
};

void Display(const Person& p, const Student& s)
{
	cout << p._name << endl;
	cout << s._stuNum << endl;
}

int main()
{
	Person p;
	Student s;
	// 编译报错:error C2248: “Student::_stuNum”: 无法访问 protected 成员
	// 解决方案:Display也变成Student 的友元即可
	Display(p, s);

	return 0;
}

6. 继承与静态成员

基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派⽣类,都只有⼀个static成员实例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person
{
public:
	string _name;
	static int _count;
};
int Person::_count = 0;

class Student : public Person
{
protected:
	int _stuNum;
};

int main()
{
	Person p;
	Student s;

	// 这里的运行结果可以看到非静态成员_name的地址是不一样的
// 说明子类继承下来了,父子类对象各有一份
	cout << &p._name << endl;
	cout << &s._name << endl;

	// 这里的运行结果可以看到静态成员_count的地址是一样的
	// 说明子类和父类共用同一份静态成员
	cout << &p._count << endl;
	cout << &s._count << endl;

	// 公有的情况下,父子类指定类域都可以访问静态成员
	cout << Person::_count << endl;
	cout << Student::_count << endl;

	Person::_count++;

	cout << p._count << endl;
	cout << s._count << endl;

	return 0;
}

运行结果:

 7. 多继承及其菱形继承问题

7.1 继承模型

单继承:⼀个派⽣类只有⼀个直接基类时称这个继承关系为单继承

多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯。

菱形继承:菱形继承是多继承的⼀种特殊情况。菱形继承的问题,从下⾯的对象成员模型构造,可以看出菱形继承有数据冗余和⼆义性的问题,在Assistant的对象中Person成员会有两份。⽀持多继承就 ⼀定会有菱形继承,像Java就直接不⽀持多继承,规避掉了这⾥的问题,所以实践中我们也是不建议 设计出菱形继承这样的模型的。

class Person { public:string _name; // 姓名 }; class Student : public Person { protected:     int _num; //学号 }; class Teacher : public Person { protected:     int _id; // 职⼯编号 }; class Assistant : public Student, public Teacher { protected:     string _majorCourse; // 主修课程 }; int main() {     // 编译报错:error C2385: 对“_name”的访问不明确     Assistant a;     a._name = "peter";     // 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题,但是数据冗余问题⽆法解决     a.Student::_name = "xxx";     a.Teacher::_name = "yyy";     return 0; }

7.2 虚继承

很多⼈说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可以认为是C++的缺陷之⼀,后来的⼀些编程语⾔都没有多继承,如Java。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person
{
public:
	string _name; // 姓名
	/*int _tel;
	int _age;
	string _gender;
	string _address;*/
// ...
};
// 使⽤虚继承Person类
class Student : virtual public Person
{
protected:
	int _num; //学号
};
// 使⽤虚继承Person类
class Teacher : virtual public Person
{
protected:
	int _id; // 职⼯编号
};
// 教授助理
class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};
int main()
{
	// 使⽤虚继承,可以解决数据冗余和⼆义性
	Assistant a;
	a._name = "peter";
	return 0;
}

我们可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,⽆论是使⽤还是底层都会复杂很多。当然有多继承语法⽀持,就⼀定存在会设计出菱形继承,像Java是不⽀持多继承的, 就避开了菱形继承。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person
{
public:
	Person(const char* name)
		:_name(name)
	{}

	string _name; // 姓名
	/*int _tel;
	int _age;
	string _gender;
	string _address;*/
	// ...
};

class Student : virtual public Person
{
public:
	Student(const char* name, int num = 0)
		:Person(name)
		,_num(num)
	{}
protected:
	int _num; //学号
};

class Teacher : virtual public Person
{
public:
	Teacher(const char* name, int id = 1)
		:Person(name)
		, _id(id)
	{}
protected:
	int _id; // 职工编号
};

// 不要去玩菱形继承
class Assistant : public Student, public Teacher
{
public:
	Assistant(const char* name1, const char* name2, const char* name3)
		:Student(name1)
		,Teacher(name2)
		,Person(name3)
	{}
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	// 思考⼀下这⾥a对象中_name是"张三", "李四", "王五"中的哪⼀个?
	Assistant a("张三", "李四", "王五");

	return 0;
}

7.3 练习题

多继承中指针偏移问题?下⾯说法正确是( )

A:p1 == p2 == p3         B:p1 < p2 < p3         C:p1 == p3 != p2         D:p1 != p2 != p3

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;
return 0;
}

8. 继承和组合

public继承是⼀种is-a的关系。也就是说每个派⽣类对象都是⼀个基类对象。

组合是⼀种has-a的关系。假设B组合了A,每个B对象中都有⼀个A对象。

继承允许你根据基类的实现来定义派⽣类的实现。这种通过⽣成派⽣类的复⽤通常被称为⽩箱复⽤ (white-box reuse)。术语“⽩箱”是相对可视性⽽⾔:在继承⽅式中,基类的内部细节对派⽣类可⻅ 。继承⼀定程度破坏了基类的封装,基类的改变,对派⽣类有很⼤的影响。派⽣类和基类间的依 赖关系很强,耦合度⾼。

对象组合是类继承之外的另⼀种复⽤选择。新的更复杂的功能可以通过组装或组合对象来获得。对 象组合要求被组合的对象具有良好定义的接⼝。这种复⽤⻛格被称为⿊箱复⽤(black-box reuse), 因为对象的内部细节是不可⻅的。对象只以“⿊箱”的形式出现。 组合类之间没有很强的依赖关 系,耦合度低。优先使⽤对象组合有助于你保持每个类被封装。

优先使⽤组合,⽽不是继承。实际尽量多去⽤组合,组合的耦合度低,代码维护性好。不过也不太 那么绝对,类之间的关系就适合继承(is-a)那就⽤继承,另外要实现多态,也必须要继承。类之间的关系既适合⽤继承(is-a)也适合组合(has-a),就⽤组合。

// Tire(轮胎)和Car(⻋)更符合has-a的关系 class Tire { protected:     string _brand = "Michelin"; // 品牌     size_t _size = 17; // 尺⼨ }; class Car { protected:     string _colour = "⽩⾊"; // 颜⾊     string _num = "陕ABIT00"; // ⻋牌号     Tire _t1; // 轮胎     Tire _t2; // 轮胎     Tire _t3; // 轮胎     Tire _t4; // 轮胎 }; class BMW : public Car { public:     void Drive() { cout << "好开-操控" << endl; } }; // Car和BMW/Benz更符合is-a的关系 class Benz : public Car { public:     void Drive() { cout << "好坐-舒适" << endl; } }; template<class T> class vector {}; // stack和vector的关系,既符合is-a,也符合has-a template<class T> class stack : public vector<T> {}; template<class T> class stack { public:     vector<T> _v; }; int main() {     return 0; }

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅
C++中的继承是面向对象编程(OOP)的一个核心概念,它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法。继承促进了代码的重用性和扩展性。
逆向-落叶
2024/11/20
1600
深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅
【C++】继承
继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称⼦类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用,继承是类设计层次的复用。
用户11290673
2024/09/25
1510
【C++】继承
【C++】———— 继承
看一下这张图片,就可以看出来,使用Student定义的s,就继承了Person的成员和函数。
用户11036582
2024/07/09
1410
【C++】———— 继承
深度剖析C++继承
可以看见Student对象s不止有着从Person继承的_name和_age,还有自己的_stuid,同理可以看见Teacher对象t不止有着从Person继承的_name和_age,还有自己的_jobid。
小灵蛇
2024/06/06
1120
深度剖析C++继承
【C++阅览室】C++三大特性之继承
继承在C++中是十分重要的,它在面向对象程序设计时使代码可以复用的重要手段。继承可以允许程序员在保持原有类的特性下进行拓展,增加新的功能,这样产生的类,称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简到繁的过程。在此之前,我们接触到的都是函数的复用,继承是类设计之间的复用。
小文要打代码
2024/10/16
1200
【C++阅览室】C++三大特性之继承
【C++进阶】继承
继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称子类。 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用,继承是类设计层次的复用。
_小羊_
2024/10/16
1050
【C++进阶】继承
C++进阶:详细讲解继承
现在也是结束了初阶部分的内容,今天开始就进入进阶部分了。一刻也没有为初阶的结束而哀悼,立刻赶来“战场”的是进阶部分里的继承
是Nero哦
2024/03/11
1950
C++进阶:详细讲解继承
C++继承(多继承、菱形继承?)
继承(inheritance)机制是面向对象程序设计,使代码可以复用的最重要的手段。它允许程序员在保持原有类特性的基础上进行扩展,以增加功能。这样产生新的类,称为派生类。
利刃大大
2023/04/12
2.2K0
C++继承(多继承、菱形继承?)
【c++】C++中的继承&&菱形继承详解
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用
用户10925563
2024/06/04
2510
【c++】C++中的继承&&菱形继承详解
【C++】类和对象之继承
简单来说就是类似于在一个类中包含了另一个类的成员函数和成员变量以及对应的访问权限。
啊QQQQQ
2024/11/19
1510
【C++】类和对象之继承
【C++】继承(下)
派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
s-little-monster
2024/09/27
1420
【C++】继承(下)
C++:继承与派生
为什么会有继承这样的语法呢??试想这样一个场景:假设我们这个App需要去获取不同类型用户的数据,并进行分类,那么就需要我们去写对应不同的类,比如说学生、老师、军人、公司职工…………每个类都需要有名字、联系方式、家庭住址、年龄……,我们会发现这样每个类都要写一份,非常冗余,于是我们的祖师爷为了解决这个问题,设计出了继承的语法,比如说用户的共同点是都是用户,我们就可以写一个关于人的类,作为基类,而不同类型用户就作为基类的派生类,去继承基类的成员,从而达到我们的目的。
小陈在拼命
2024/03/12
2470
C++:继承与派生
继承
继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
海盗船长
2020/08/27
8330
C++ —— 关于继承(inheritance)
使用类模版模拟实现一个栈,可以使用vector/list/deque来当做底层容器,核心就是类模版的继承
迷迭所归处
2024/11/19
1190
C++ —— 关于继承(inheritance)
【继承】—— 我与C++的不解之缘(十九)
简单来说,对于两个类(甚至多个),它们直接有一些相同的成员;这样设计是有些冗余的。
星辰与你
2024/12/29
1880
【继承】—— 我与C++的不解之缘(十九)
继承机制深度解析:从基础到进阶的完整指南
继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。继承呈现了⾯向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复⽤,继承是类设计层次的复⽤。
用户11286421
2024/11/21
2600
继承机制深度解析:从基础到进阶的完整指南
C++:继承
继承(inheritance)机制是面向对象程序设计使代码可以复用的重要手段,它允许程序员在保持着类特性的基础上进行扩展,增加功能,这样产生新的类,称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。之前用的比较多的是函数复用,继承是类设计层次的复用。
HZzzzzLu
2024/11/26
1460
C++:继承
【C++】继承
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
zxctscl
2024/04/20
1710
【C++】继承
C++进阶-继承
C++进阶-继承 零、前言 一、继承的概念和定义 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承和友元 六、继承和静态成员 七、菱形继承和虚拟继承 八、继承和组合 九、继承相关面试题 零、前言 从本章开始,我们已经达到了C++的入门水平,开始向进阶进发,而本章则是介绍学习C++的继承 一、继承的概念和定义 概念: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生
用户9645905
2022/11/30
4970
C++进阶-继承
【C++航海王:追寻罗杰的编程之路】继承你学会了么?
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行拓展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前使用的复用都是函数复用,继承是类设计层次的复用。
枫叶丹
2024/06/04
1620
【C++航海王:追寻罗杰的编程之路】继承你学会了么?
相关推荐
深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验