基类总是要写虚析构函数
class A {
public:
virtual ~A() = default;
};
通过设置析构函数为纯虚函数来让类称为抽象基类
代码
class A {
public:
virtual ~A() = 0 {}
};
函数virtual属性的传递性
class A {
public:
virtual void fun() { std::cout << "fun" << std::endl; }
};
class B : public A {
public:
// 没有写virtual,却有virtual属性
void fun() { std::cout << "fun2" << std::endl; }
};
class C : public B {
public:
// 没有写virtual,却有virtual属性
void fun() { std::cout << "fun3" << std::endl; }
};
int main(void) {
B * b = new C;
b->fun();
delete b;
return system("pause");
}
拷贝移动控制成员的定义
简述
拷贝移动控制成员包括:拷贝构造函数、拷贝赋值函数、移动构造函数、移动赋值函数。
代码
operator=返回值有错误,待修正
class A {
public:
// 拷贝构造函数
A(const A & a) = default;
// 移动构造函数
A(A && a) = default;
// 拷贝赋值函数
A & operator=(const A & a) { return (*this); }
// 移动赋值函数
A & operator=(A &&) = default;
virtual ~A() = default;
};
class B : public A {
public:
// 调用基类的拷贝构造函数
B(const B & b) : A(b) {}
// 调用基类的移动拷贝构造函数
B(B && b) : A(std::move(b)) {}
// 不要忘记调用基类的拷贝赋值函数
B & operator=(const B & b) {
A::operator=(b);
// 执行一些操作...
return (*this);
}
B & operator=(B && b) {
// 不要忘记调用基类的移动赋值函数
A::operator=(std::move(b));
// 执行一些操作...
return (*this);
}
};
单继承中,继承基类构造函数
代码
class A {
public:
A() = default;
A(int) { std::cout << "A(int)" << std::endl; }
A(double) { std::cout << "A(double)" << std::endl; }
};
class B : public A {
public:
using A::A;
B(int) { std::cout << "B(int)" << std::endl; };
};
int main() {
B b1(9);
B b2(9.9);
return system("pause");
}
输出结果
B(int)
A(double)
基类成员的可访问性
class A {
public:
void abc() {}
};
class B : public A {
public:
void fun1() { abc(); }
};
class C : protected A {
public:
void fun1() { abc(); }
};
class D : private A {
public:
void fun1() { abc(); }
};
class BB : public B {
public:
void fun2() { abc(); }
};
class CC : public C {
public:
void fun2() { abc(); }
};
class DD : public D {
public:
void fun2() { abc(); } // 无法访问
};
int main() {
B b;
b.abc();
C c;
c.abc(); // 无法访问
D d;
d.abc(): // 无法访问
return system("pause");
}
构造或析构时,不呈现多态性
简述
在构造或析构基类时,如果调用了某个虚函数,则这个虚函数使用与当前构造函数或析构函数所属类型相对应的虚函数版本。
代码
class A {
public:
// 在构造函数体内,fun()函数不会表现出多态性。
A(int) { fun(); }
virtual void fun() { std::cout << "A::fun()" << std::endl; }
};
class B : public A {
public:
B() : A(1) {}
virtual void fun() { std::cout << "B::fun()" << std::endl; }
};
int main() {
B b;
return system("pause");
}
输出结果
A::fun()
访问控制符仅作用于自身成员和基类成员
class A {
protected:
int a;
};
class B : public A {
public:
void fun(A & temp) {
a = 3;
temp.a = 3; // 错误
}
};
改变基类成员的可访问性
class A {
public:
int i;
int j;
};
class B : private A { // 私有继承
public:
using A::i; // 改变i的访问控制为public
protected:
using A::j; // 改变i的访问控制为protected
};
int main() {
B b;
b.i = 3;
return system("pause");
}
重写函数发生的遮掩问题及其解决方案
class A {
public:
virtual void fun() { do_fun(); }
virtual void fun(int a) { do_fun(a); }
virtual void fun(char c) { do_fun(c); }
protected:
virtual void do_fun() {}
virtual void do_fun(int) {}
virtual void do_fun(char) {}
};
class B : public A {
public:
void fun() {}
};
int main() {
B b;
// 继承其中一个fun函数,导致遮掩了其他基类fun函数版本。
b.fun('c');
// 解决方案:通过使fun()函数调用dofun(),而派生类重载do_fun()函数来避免遮掩问题。
return system("pause");
}
delete基类指针数组是未定义行为
class A {
};
class B : public A {
};
int main() {
A * a = new B[10];
delete[] a; // 错误
return system("pause");
}
不能使用间接非虚基类的构造函数
class A {
public:
A() {}
};
class B : public A {
public:
// 允许使用直接非虚基类构造函数
B() : A() {}
};
class C : public B {
public:
// 不允许使用间接非虚基类构造函数
C() : A() {}
};