目录
第一题(哪些成员变量需要在初始化列表初始化)
第二题(多态的条件)
第三题(多态的条件(通过父类对象调用的全部都是父类的方法))
第四题(菱形继承,虚拟继承的初始化顺序)
第一题(哪些成员变量需要在初始化列表初始化)
有一个类B继承自类A,他们数据成员如下:
class A {
...
private:
int a;
};
class B : public A {
...
private:
int a;
public:
const int b;
A &c;
static const char* d;
B* e;
}
则构造函数中,成员变量一定要通过初始化列表来初始化的是
A a b c
B b c e
C b c d e
D c e
E b d
F b c
哪些成员必须在初始化列表的位置初始化?
1.const修饰的成员变量(常量数据是不允许修改的,所以只能通过参数列表初始化)
2.引用类型的成员变量(引用不能为空,必须要引用一个对象)
3.类的类型对象,该类没有默认的构造函数。(比方说我们的B类中没有默认构造函数,有一个B(int x)的构造函数,那么我们的另外一个类A去调用我们这个类B的时候,就必须在初始化列表的位置初始化这个B)
A() :B(30) { }
同【笔试题】【day7】_桜キャンドル淵的博客-CSDN博客
中的第四题
但是这里的d也是const的呀,需不需要在参数列表的位置初始化?
静态成员不能再类的内部初始化!
因为静态的成员的初始化必须要放在类的外面,使用类访问限定符指明。
F
第二题(多态的条件)
class Base {
public:
Base(int j): i(j) {}
virtual~Base() {}
void func1() {
i *= 10;
func2();
}
int getValue() {
return i;
}
protected:
virtual void func2() {
i++;
}
protected:
int i;
};
class Child: public Base {
public:
Child(int j): Base(j) {}
void func1() {
i *= 100;
func2();
}
protected:
void func2() {
i += 2;
}
};
int main() {
Base * pb = new Child(1);
pb->func1();
cout << pb->getValue() << endl; delete pb;
}
A 11
B 101
C 12
D 102
这里我们的Base *pd=new Child(1)
会调用子类的Child的构造函数,
在子类的构造的过程中,其初始化列表中会构造一个Base(j)
这里的Base(j)又会初始化i为j,所以我们此时的i为1
然后pb->func1()
由于我们的pb是父类的指针,指向的是子类的对象,但是我们的fun1再Base前面并没有加上virtual,所以不构成多态!所以这里还是按照父类的指针就调用父类的方法
此时我们的i*=10,变成了10,然后调用func2函数
但是我们观察到这个func2函数基类有virtual,并且这是一个父类指针,指向子类,满足多态的条件,所以这里构成多态,也就是调用子类的func2函数,也就是我们下面的这个func2(),所以我们的i+=2变成了12
C
第三题(多态的条件(通过父类对象调用的全部都是父类的方法))
#include<iostream>
#include<string>
using namespace std;
class B0 {
public:
virtual void display() {
cout << "B0::display0" << endl;
}
};
class B1 :public B0 {
public:
void display() { cout << "B1::display0" << endl; }
};
class D1 : public B1 {
public:
void display() {
cout << "D1::display0" << endl;
}
};
void fun(B0 ptr) {
ptr.display();
}
int main() {
B0 b0;
B1 b1;
D1 d1;
fun(b0);
fun(b1);
fun(d1);
}
A B0::display0 B0::display0 B0::display0
B B0::display0 B0::display0 D1::display0
C B0::display0 B1::display0 D1::display0
D B0::display0 B1::display0 B1::display0
这里我们观察到我们的fun()是一个全局函数
然后我们传入的对象都会被赋值给一个父类对象B0
然后再用这个父类对象去调用display()函数
这里不满足我们多态的条件,只是静态编译,所以我们输出的三个全部都是B0::display0
(对象的调用是静态编译!不是多态)
A
第四题(菱形继承,虚拟继承的初始化顺序)
#include<iostream>
using namespace std;
class A {
public: A(const char* s) { cout << s << endl; } ~A() {}
};
class B : virtual public A {
public: B(const char* s1, const char* s2) :A(s1) { cout << s2 << endl; }
};
class C : virtual public A {
public: C(const char* s1, const char* s2) :A(s1) { cout << s2 << endl; }
};
class D : public B, public C {
public: D(const char* s1, const char* s2, const char* s3, const char* s4) :B(s1, s2), C(s1, s3), A(s1)
{ cout << s4 << endl; }
};
int main() { D* p = new D("class A", "class B", "class C", "class D"); delete p; return 0;
}
A class A
class B
class C
class D
B class D
class B
class C
class A
C class D
class C
class B
class A
D class A
class C
class B
class D
我们这里的初始化的顺序是按照这里继承的顺序来的,首先我们继承了B类
但是我们的B类中又需要有一个A类,A类的构造又需要有一个字符串,所以上面的s1就是我们A类的构造函数中的字符串也就是classA最先被打印出来
然后构造B,打印classB
然后构造C,因为我们的C这里是虚拟继承的,并不会再去构造一个A,而是直接和B共用同一个A。打印classC
最后打印构造D类,打印classD
A