C++ 支持多重继承。所谓的多重继承指的是子类同时继承多个父类,此时子类拥有所有父类的所有成员。
继承方式如下:
class Derived : public Baes_A, public Baes_B
{
...
}
多重继承会造成不同的父类指针(或引用)指向(或引用)子类对象时,实际所指向(或引用)的子类地址不一致。如此一来,假设程序中想通过判断两个指针是否指向相同的对象时,会发生错误的判定导致程序逻辑错误。而这个问题是无解的。因此, C++ 不提倡使用多重继承,C++ 派送出来的如 JAVA、C# 等都不支持多重继承。
class Base_A
{
private:
int mVar;
};
class Base_B
{
private:
int mVar;
};
class Derived : public Base_A, public Base_B
{
private:
int mVar;
};
int main(int argc, char *argv[])
{
Derived obj;
Base_A* p_A = &obj;
Base_B* p_B = &obj;
if(reinterpret_cast<void*>(p_A) == reinterpret_cast<void*>(p_B))
{
cout << "*p_A equal to *p_B" << endl;
}
else
{
cout << "p_A = " << p_A << endl; // p_A = 0x7ffe1e60
cout << "p_B = " << p_B << endl; // p_B = 0x7ffe1e64
}
}
在多重继承中,还有一个陷阱,称为菱形继承。所谓的菱形继承通俗描述为,由一个基类派生出派生类 A 与派生类 B,然后派生类 C 再继承于派生类 A 与 B,这样一来便会产生冗余的成员。
class Base
{
public:
void Print()
{
cout << "in Base" << endl;
}
};
class Derived_A : public Base
{
};
class Derived_B : public Base
{
};
class Derived_C : public Derived_A, public Derived_B
{
};
int main(int argc, char *argv[])
{
Derived_C obj;
// obj.Print(); // error: request for member ‘Print’ is ambiguous
}
从以上可知,Derived_C 继承了 Derived_A 与 Derived_B,自然而然继承了他们的 Print() 成员函数,此时 Derived_C 中存在两个 Print() 成员函数,函数调用时编译器并不知道应该调用哪一个 Print()。
解决冗余的方法是使用虚继承。虚继承的原理可参考:从内存布局看C++虚继承的实现原理
class Base
{
public:
void Print()
{
cout << "in Base" << endl;
}
};
class Derived_A : virtual public Base
{
};
class Derived_B : virtual public Base
{
};
class Derived_C : public Derived_A, public Derived_B
{
};
int main(int argc, char *argv[])
{
Derived_C obj;
obj.Print(); // in Base
}
当子类继承了多个含虚函数的父类时,子类会产生多个对应的虚函数表,每个虚函数表中分别记录与父类对应的虚函数地址。当通过子类访问父类的虚函数时,如果对父类指针使用强制类型转换为另一个父类指针,此时只会进行单纯的地址传递,不会进行类型检查,进而造成错误的指针指向。因此,应使用 C++ 提供的关键字 dynamic_cast 进行指针类型转换,此时转换会多进行一次类型检查,使得指针指向正确的地址。
class Base_A
{
public:
virtual void Print_A()
{
cout << "in Base_A" << endl;
}
};
class Base_B
{
public:
virtual void Print_B()
{
cout << "in Base_B" << endl;
}
};
class Derived : public Base_A, public Base_B
{
};
int main(int argc, char *argv[])
{
cout << "sizeof(Derived) = "
<< sizeof(Derived) << endl; // sizeof(Derived) = 8 ,两个虚函数表指针
Derived obj;
Base_A* p_A = &obj;
p_A->Print_A(); // in Base_A
// p_A->Print_B(); // error: ‘class Base_A’ has no member named ‘Print_B’
Base_B* p_B = &obj;
p_B->Print_B(); // in Base_B
// p_B->Print_A(); // error: ‘class Base_B’ has no member named ‘Print_A’
p_B = (Base_B*)p_A;
p_B->Print_B(); // in Base_A
p_B = dynamic_cast<Base_B*>(p_A);
p_B->Print_B(); // in Base_B
}
在工程中,一般使用“单继承 + 多接口”来代替多继承。由于接口是无实例的,因此形式上还是单继承。一般地,会在父类中定义一个成员函数 equal() 来判断指针是否指向当前对象,且关于父类指针类型之间的转换需要使用关键字 dynamic_cast 完成。
class Base
{
protected:
int mVar;
public:
Base(int num = 0)
{
mVar = num;
}
int GetmVar()
{
return mVar;
}
bool equal(Base* obj)
{
return (this == obj);
}
};
class Interface_A
{
public:
virtual void add(int num) = 0;
virtual void minus(int num) = 0;
};
class Interface_B
{
public:
virtual void multiply(int num) = 0;
virtual void divide(int num) = 0;
};
class Derived : public Base, public Interface_A, public Interface_B
{
public:
Derived(int num = 0) : Base(num)
{
}
virtual void add(int num)
{
mVar += num;
}
virtual void minus(int num)
{
mVar -= num;
}
virtual void multiply(int num)
{
mVar *= num;
}
virtual void divide(int num)
{
if( num != 0 )
{
mVar /= num;
}
}
};
int main()
{
Derived obj(100);
Derived* p = &obj;
Interface_A* pInt_A = &obj;
Interface_B* pInt_B = &obj;
cout << "p->GetmVar() = " << p->GetmVar() << endl; // p->GetmVar() = 100
pInt_A->add(10);
cout << "p->GetmVar() = " << p->GetmVar() << endl; // p->GetmVar() = 110
pInt_B->divide(11);
cout << "p->GetmVar() = " << p->GetmVar() << endl; // p->GetmVar() = 10
pInt_A->minus(5);
cout << "p->GetmVar() = " << p->GetmVar() << endl; // p->GetmVar() = 5
pInt_B->multiply(8);
cout << "p->GetmVar() = " << p->GetmVar() << endl; // p->GetmVar() = 40
cout << "(pInt_A == p) is " << p->equal(dynamic_cast<Base*>(pInt_A)) << endl; // (pInt_A == p) is 1
cout << "(pInt_B == p) is " << p->equal(dynamic_cast<Base*>(pInt_B)) << endl; // (pInt_B == p) is 1
return 0;
}