c++的继承机制通过派生类继承基类的成员实现代码重用和多态性,使用冒号指定继承方式,其中public继承保持基类成员访问权限不变,protected继承将基类public成员变为protected,private继承将基类public和protected成员均变为private,基类private成员在派生类中不可直接访问;多态通过虚函数实现,允许基类指针或引用调用派生类重写的虚函数,从而实现运行时动态绑定;多重继承允许一个类继承多个基类,但可能引发菱形继承问题,可通过虚继承解决,但会增加复杂性和性能开销,因此建议优先使用组合而非多重继承。

C++的继承机制允许你创建一个新类(派生类),它继承了现有类(基类)的特性。这不仅节省了代码,还实现了代码重用和多态性。理解基类和派生类的访问权限是掌握继承的关键。
解决方案
C++通过使用冒号
:来实现继承。基本的语法如下:
立即学习“C++免费学习笔记(深入)”;
class 派生类名 : 访问修饰符 基类名 {
// 派生类的成员
};其中,
访问修饰符可以是
public、
protected或
private。 这个修饰符决定了基类成员在派生类中的访问权限。
访问权限详解:
public
继承: 基类的public
成员在派生类中仍然是public
,基类的protected
成员在派生类中仍然是protected
,基类的private
成员在派生类中不可直接访问(但可以通过基类的public
或protected
成员函数访问)。 这通常是希望派生类完全拥有基类的接口时使用的。protected
继承: 基类的public
成员在派生类中变成protected
,基类的protected
成员在派生类中仍然是protected
,基类的private
成员在派生类中不可直接访问。protected
继承通常用于希望基类的接口对派生类的进一步派生类可用,但不想暴露给外部用户的情况。private
继承: 基类的public
成员在派生类中变成private
,基类的protected
成员在派生类中变成private
,基类的private
成员在派生类中不可直接访问。private
继承是最严格的继承方式,基类的接口完全被隐藏在派生类内部。
示例代码:
#include <iostream>
class Base {
public:
int publicVar;
protected:
int protectedVar;
private:
int privateVar;
public:
Base(int a, int b, int c) : publicVar(a), protectedVar(b), privateVar(c) {}
void printBase() {
std::cout << "Base: public=" << publicVar << ", protected=" << protectedVar << std::endl; // 无法访问 privateVar,除非通过成员函数
}
int getPrivateVar() const { return privateVar; } // 提供一个访问私有成员的接口
};
class PublicDerived : public Base {
public:
PublicDerived(int a, int b, int c) : Base(a, b, c) {}
void printDerived() {
std::cout << "PublicDerived: public=" << publicVar << ", protected=" << protectedVar << std::endl;
//std::cout << "PublicDerived: private=" << privateVar << std::endl; // 错误:无法访问基类的私有成员
}
};
class ProtectedDerived : protected Base {
public:
ProtectedDerived(int a, int b, int c) : Base(a, b, c) {}
void printDerived() {
std::cout << "ProtectedDerived: public=" << publicVar << ", protected=" << protectedVar << std::endl;
}
};
class PrivateDerived : private Base {
public:
PrivateDerived(int a, int b, int c) : Base(a, b, c) {}
void printDerived() {
std::cout << "PrivateDerived: public=" << publicVar << ", protected=" << protectedVar << std::endl;
}
};
int main() {
PublicDerived pub(1, 2, 3);
pub.printDerived();
std::cout << "Main (PublicDerived): public=" << pub.publicVar << std::endl; // 可以访问 publicVar
ProtectedDerived pro(4, 5, 6);
pro.printDerived();
//std::cout << "Main (ProtectedDerived): public=" << pro.publicVar << std::endl; // 错误:publicVar 在这里是不可访问的
PrivateDerived pri(7, 8, 9);
pri.printDerived();
//std::cout << "Main (PrivateDerived): public=" << pri.publicVar << std::endl; // 错误:publicVar 在这里是不可访问的
Base base(10,11,12);
std::cout << "Base private variable: " << base.getPrivateVar() << std::endl; // 通过公共接口访问私有成员
return 0;
}为什么需要继承?继承解决了什么问题?
继承的核心目的是代码重用和实现多态。想象一下,如果没有继承,你需要为每个相似的类编写几乎相同的代码。继承允许你创建一个通用的基类,然后通过派生类来扩展和修改其行为,避免代码冗余。多态性则允许你使用基类的指针或引用来操作派生类的对象,从而实现更灵活的设计。例如,你可以有一个
Animal基类,然后有
Dog和
Cat派生类。你可以创建一个
Animal指针数组,其中存储
Dog和
Cat对象,并调用它们的
makeSound()方法,而不需要知道它们具体的类型。
虚函数在继承中的作用是什么?如何实现多态?
虚函数是实现多态的关键。 在一个基类中声明为
virtual的函数,可以在派生类中被重写(override)。当通过基类的指针或引用调用虚函数时,实际执行的是派生类中的版本(如果派生类重写了该函数)。
#include <iostream>
class Animal {
public:
virtual void makeSound() {
std::cout << "Generic animal sound" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
std::cout << "Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
std::cout << "Meow!" << std::endl;
}
};
int main() {
Animal* animals[3];
animals[0] = new Animal();
animals[1] = new Dog();
animals[2] = new Cat();
for (int i = 0; i < 3; ++i) {
animals[i]->makeSound(); // 调用的是实际对象的 makeSound() 方法
delete animals[i];
}
return 0;
}在这个例子中,尽管我们使用的是
Animal指针,但
makeSound()函数的行为会根据实际对象的类型而改变。这就是多态的威力。
多重继承是什么?它有哪些潜在的问题?
多重继承是指一个类可以同时继承多个基类。虽然这提供了更大的灵活性,但也可能导致一些问题,比如菱形继承(Diamond Problem)。菱形继承指的是一个类
D同时继承了
B和
C,而
B和
C又都继承自
A。 如果
A中有一个成员变量,那么
D中就会有两个
A的实例,这可能会导致二义性和不必要的内存消耗。
为了解决菱形继承的问题,可以使用虚继承。虚继承确保在继承链中只有一个基类的实例。
#include <iostream>
class A {
public:
int data;
};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {
public:
void setData(int value) {
A::data = value; // 只有一个 A 的实例,所以没有二义性
}
int getData() {
return A::data;
}
};
int main() {
D d;
d.setData(10);
std::cout << "Data: " << d.getData() << std::endl;
return 0;
}尽管虚继承解决了菱形继承的问题,但它也增加了代码的复杂性,并且可能会影响性能。因此,在设计类层次结构时,应该谨慎使用多重继承。 尽量使用组合(Composition)来代替继承,除非确实需要继承所提供的多态性。










