一.被遗弃的多重继承
Q:C++中是否允许一个类继承自多个父类? 在实际的C++编译环境中,C++是支持编写多重继承的代码 1.一个子类可以拥有多个父类 2.子类拥有所有父类的成员变量 3.子类继承所有父类的成员函数 4.子类对象可以当作任意父类对象使用 多重继承的语法规则 但是在多重继承中会存在许多问题 Q:多重继承得到的对象可能拥有不同的地址 代码示例
#include <iostream>
#include <string>
using namespace std;
class BaseA
{
int ma;
public:
BaseA(int a)
{
ma = a;
}
int getA()
{
return ma;
}
};
class BaseB
{
int mb;
public:
BaseB(int b)
{
mb = b;
}
int getB()
{
return mb;
}
};
class Derived : public BaseA, public BaseB//拥有两个父类
{
int mc;
public:
Derived(int a, int b, int c) : BaseA(a), BaseB(b)
{
mc = c;
}
int getC()
{
return mc;
}
void print()
{
cout << "ma = " << getA() << ", "
<< "mb = " << getB() << ", "
<< "mc = " << mc << endl;
}
};
int main()
{
cout << "sizeof(Derived) = " << sizeof(Derived) << endl;
Derived d(1, 2, 3);
d.print();
cout << "d.getA() = " << d.getA() << endl;
cout << "d.getB() = " << d.getB() << endl;
cout << "d.getC() = " << d.getC() << endl;
cout << endl;
//两个父类指针指向同一个对象
BaseA* pa = &d;
BaseB* pb = &d;
cout << "pa->getA() = " << pa->getA() << endl;
cout << "pb->getB() = " << pb->getB() << endl;
cout << endl;
void* paa = pa;
void* pbb = pb;
if( paa == pbb )
{
cout << "Pointer to the same object!" << endl;
}
else
{
cout << "Error" << endl;
}
cout << "pa = " << pa << endl;
cout << "pb = " << pb << endl;
cout << "paa = " << paa << endl;
cout << "pbb = " << pbb << endl;
return 0;
}
运行结果 我们可以看到在条件判断语句中,paa与pbb指向的是同一个对象,按理说应该打印相同时的语句,可是却打印错误,从接下来的地址打印结果是不一样的,这就造成了多重继承的问题--同一个对象取地址之后进行初始化,但是pa与pb打印的结果却不同 Q:多重继承可能产生冗余的成员 代码实现
#include <iostream>
#include <string>
using namespace std;
class People
{
string m_name;
int m_age;
public:
People(string name, int age)
{
m_name = name;
m_age = age;
}
void print()
{
cout << "Name = " << m_name << ", "
<< "Age = " << m_age << endl;
}
};
class Teacher : virtual public People
{
public:
Teacher(string name, int age) : People(name, age)
{
}
};
class Student : virtual public People
{
public:
Student(string name, int age) : People(name, age)
{
}
};
class Doctor : public Teacher, public Student
{
public:
Doctor(string name, int age) : Teacher(name, age), Student(name, age), People(name, age)
{
}
};
int main()
{
Doctor d("Delphi", 33);
d.print();
return 0;
}
由运行结果可以知道,在进行print时出错,这是因为Doctor由于继承,会有两个打印的函数,所以通过作用域分辨符进行改正 由于冗余,打印的结果可能不一样 当多重继承关系出现闭合时将产生暑假冗余的问题 解决方案:虚继承
二.经典问题分析
一.关于动态内存分配 Q:new和malloc的区别?delete和free的区别? A.new关键字与malloc函数的区别 1.new关键字是C++的一部分,malloc是由C库提供的函数 2.new以具体类型为单位进行内存分配,malloc以字节为单位进行内存分配 3.new在申请内存空间时可进行初始化,malloc仅根据需要申请定量的内存空间 代码示例
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Test
{
int* mp;
public:
Test()
{
cout << "Test::Test()" << endl;
mp = new int(100);
cout << *mp << endl;
}
~Test()
{
delete mp;
cout << "~Test::Test()" << endl;
}
};
int main()
{
Test* pn = new Test;
Test* pm = (Test*)malloc(sizeof(Test));
delete pn;
free(pm);
return 0;
}
运行结果 关于动态内存分配 new和malloc的区别 1.new在所有C++编译器中都能被支持,malloc在某些系统开发中是不能调用的 2.new能够触发析构函数的调用,malloc仅分配需要的内存空间 3.对象的创建只能使用new,malloc不适合面向对象开发 delete和free的区别 1.delete在所有C++编译器中都被支持,free在某些系统开发中是不能调用的 2.delete能够触发析构函数的调用,free仅归还之前的分配空间 3.对象的销毁只能使用delete,free不适合面向对象的开发
B.关于虚函数 Q:构造函数是否可以成为虚函数?析构函数是否可以成为虚函数? 1.构造函数不可能成为虚函数--在构造函数执行结束后,虚函数表指针才会被正确的初始化 2.析构函数可以成为虚函数--建议在设计类时将析构函数声明为虚函数
Q:构造函数中是否可以发生多态?析构函数是否可以发生多态? 1.构造函数中不可能发生多态行为--在构造函数执行时,虚函数表指针未被正确初始化 2.析构函数在不可能发生多态行为--在析构函数执行时,虚函数表指针已经被销毁 C.关于继承中的强制类型转换 1.dynamic_cast是与继承相关的类型转换关键字,并且要求相关的类中必须有虚函数 2.用于直接或者间接继承关系的指针之间 编译器会检查dynamic_cast的使用是否正确,类型转换的结果只可能在运行的阶段才能得到 代码示例
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}
virtual ~Base()//析构虚函数
{
cout << "Base::~Base()" << endl;
}
};
class Derived : public Base
{
};
int main()
{
Base* p = new Derived;//指向的是子类对象
Derived* pd = dynamic_cast<Derived*>(p);//强制转换
cout<<"pd="<<pd<<endl;
if( pd != NULL )
{
cout << "pd = " << pd << endl;
}
else
{
cout << "Cast error!" << endl;
}
delete p;
return 0;
}
将其修改之后的打印结果比较 我们可以知道不能将子类指针对象指向父类,产生的对象时无效的