1. 子类永远都不会主动调用到父类的拷贝构造函数和拷贝赋值运算符
由以下示例可以看出调用子类Car
的拷贝构造函数和拷贝赋值运算符的时候并不会调用父类Vehicle
的拷贝构造函数和拷贝赋值运算符(Vehicle
的拷贝构造函数和拷贝赋值运算符都是delete
的。)。
#include <iostream>
class Vehicle{
public:
//Vehicle() = default;
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
//Vehicle(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Vehicle(const Vehicle& vehicle) = delete;
//Vehicle& operator=(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
// return *this;
//}
Vehicle& operator=(const Vehicle& vehicle) = delete;
private:
std::string band_;
};
class Car: public Vehicle{
public:
//Car() = default;
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called.\n";
}
Car(const Car& car): Vehicle("Tesla"){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
//Car(const Car& car){
// name_ = car.name_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Car& operator=(const Car& car){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
private:
std::string name_;
};
int main(){
//Vehicle vec1("BYD");
//Vehicle vec2(vec1);
//vec2 = vec1;
std::cout << std::string(40, '-') << std::endl;
Car car1("BYD");
Car car2(car1); // 调用父类的构造函数、子类的拷贝构造,(不会调用,也不需要父类的拷贝构造)
car2 = car1; // 调用子类的拷贝赋值运算符,(不会调用,也不需要父类的拷贝赋值运算符)
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出结果:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Vehicle ctor called.
Car::Car(const Car&)
Car& Car::operator=(const Car&)
----------------------------------------
Car dtor called.
Vehicle dtor called.
Car dtor called.
Vehicle dtor called.
1.1 应该在子类中主动调用父类的拷贝构造函数和拷贝赋值运算符
#include <iostream>
class Vehicle{
public:
//Vehicle() = default;
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
Vehicle(const Vehicle& vehicle){
band_ = vehicle.band_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
//Vehicle(const Vehicle& vehicle) = delete;
Vehicle& operator=(const Vehicle& vehicle){
band_ = vehicle.band_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
//Vehicle& operator=(const Vehicle& vehicle) = delete;
private:
std::string band_;
};
class Car: public Vehicle{
public:
//Car() = default;
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called.\n";
}
Car(const Car& car): Vehicle(car), name_(car.name_) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Car& operator=(const Car& car){
((Vehicle*)(this))->operator=(car);
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
private:
std::string name_;
};
int main(){
//Vehicle vec1("BYD");
//Vehicle vec2(vec1);
//vec2 = vec1;
std::cout << std::string(40, '-') << std::endl;
Car car1("BYD");
Car car2(car1); // 调用子类的拷贝构造函数,子类的拷贝构造函数会调用父类的拷贝构造函数
car2 = car1; // 调用子类的拷贝赋值运算符,子类的拷贝赋值运算符内部会调用父类的拷贝赋值运算符
std::cout << std::string(40, '-') << std::endl;
}
// 输出结果:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Vehicle::Vehicle(const Vehicle&)
Car::Car(const Car&)
Vehicle& Vehicle::operator=(const Vehicle&)
Car& Car::operator=(const Car&)
----------------------------------------
Car dtor called.
Vehicle dtor called.
Car dtor called.
Vehicle dtor called.
1.2 使用copy-and-swap idiom
【吴咏炜老师的解答】这样的赋值能提供强异常安全保证,也不需要自赋值检查。但性能上不及传统的实现方式。
在以面向对象方式实现的对象里,通常不会支持赋值操作。连拷贝构造都不会直接提供——因为你不知道指针/引用指向的是不是派生类对象。
参见 C++ 核心指南里的 C.67 和 C.130 条款。
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
#include <iostream>
#include <string>
class Vehicle{
public:
//Vehicle() = default;
Vehicle(const std::string& brand):brand_(brand){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
Vehicle(const Vehicle& rhs): brand_(rhs.brand_){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
//Vehicle(const Vehicle& vehicle) = delete;
Vehicle& operator=(const Vehicle& rhs){
Vehicle(rhs).swap(*this);
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
//Vehicle& operator=(const Vehicle& vehicle) = delete;
void swap(Vehicle& rhs) noexcept {
brand_.swap(rhs.brand_);
}
private:
std::string brand_;
};
class Car: public Vehicle{
public:
//Car() = default;
Car(const std::string& brand):Vehicle(brand){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called.\n";
}
Car(const Car& rhs): Vehicle(rhs), name_(rhs.name_) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Car& operator=(const Car& rhs){
Car(rhs).swap(*this);
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
void swap(Car& rhs) noexcept {
static_cast<Vehicle&>(*this).swap(rhs);
name_.swap(rhs.name_);
}
private:
std::string name_;
};
int main(){
//Vehicle vec1("BYD");
//Vehicle vec2(vec1);
//vec2 = vec1;
std::cout << std::string(40, '-') << std::endl;
Car car1("BYD");
Car car2(car1);
car2 = car1;
std::cout << std::string(40, '-') << std::endl;
}
输出结果:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Vehicle::Vehicle(const Vehicle&)
Car::Car(const Car&)
Vehicle::Vehicle(const Vehicle&)
Car::Car(const Car&)
Car dtor called.
Vehicle dtor called.
Car& Car::operator=(const Car&)
----------------------------------------
Car dtor called.
Vehicle dtor called.
Car dtor called.
Vehicle dtor called.
2. 继承体系下一般通过clone
来实现对象的拷贝
#include <iostream>
#include <memory>
class Vehicle{
public:
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
//Vehicle(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Vehicle(const Vehicle& vehicle) = delete;
//Vehicle& operator=(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
// return *this;
//}
Vehicle& operator=(const Vehicle& vehicle) = delete;
virtual std::shared_ptr<Vehicle> clone() const = 0;
private:
std::string band_;
};
class Car: public Vehicle{
public:
//Car() = default;
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called.\n";
}
Car(const Car& car): Vehicle("Tesla"){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << ", Car copy-ctor called." << std::endl;
}
//Car(const Car& car){
// name_ = car.name_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Car& operator=(const Car& car){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << ", Car copy-assignment called." << std::endl;
return *this;
}
virtual std::shared_ptr<Vehicle> clone() const override{
return std::shared_ptr<Vehicle>(new Car(*this));
}
private:
std::string name_;
};
int main(){
std::cout << std::string(40, '-') << std::endl;
Car car1("BYD");
std::shared_ptr<Vehicle> vehicle = car1.clone();
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Vehicle ctor called.
Car::Car(const Car&), Car copy-ctor called.
----------------------------------------
Car dtor called.
Vehicle dtor called.
Car dtor called.
Vehicle dtor called.
如上述示例,利用clone
对象的方式可以不用先构造出对象(通常调用拷贝构造函数)再将对象的地址赋给父类指针,而是直接使用已有对象的clone
方法返回新创建对象的地址赋给父类指针。
3. 使用CRTP来实现继承体系下对象的拷贝
#include <iostream>
#include <memory>
template<typename ChildType>
class Vehicle{
public:
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
//Vehicle(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Vehicle(const Vehicle& vehicle) = delete;
//Vehicle& operator=(const Vehicle& vehicle){
// band_ = vehicle.band_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
// return *this;
//}
Vehicle& operator=(const Vehicle& vehicle) = delete;
virtual std::shared_ptr<Vehicle> clone() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return std::shared_ptr<Vehicle>(new ChildType(static_cast<const ChildType &>(*this)));
}
private:
std::string band_;
};
class Car: public Vehicle<Car>{
public:
//Car() = default;
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called.\n";
}
Car(const Car& car): Vehicle("Tesla"){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << ", Car copy-ctor called." << std::endl;
}
//Car(const Car& car){
// name_ = car.name_;
// std::cout << __PRETTY_FUNCTION__ << std::endl;
//}
Car& operator=(const Car& car){
name_ = car.name_;
std::cout << __PRETTY_FUNCTION__ << ", Car copy-assignment called." << std::endl;
return *this;
}
private:
std::string name_;
};
int main(){
std::cout << std::string(40, '-') << std::endl;
Car car1("BYD");
std::shared_ptr<Vehicle<Car>> vehicle = car1.clone();
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出结果:
----------------------------------------
Vehicle ctor called.
Car ctor called.
std::shared_ptr<Vehicle<ChildType> > Vehicle<ChildType>::clone() const [with ChildType = Car]
Vehicle ctor called.
Car::Car(const Car&), Car copy-ctor called.
----------------------------------------
Car dtor called.
Vehicle dtor called.
Car dtor called.
Vehicle dtor called.
4.什么是CRTP?
CRTP(Curiously Recurring Template Pattern) 奇异递归模板模式。
使用CRTP的目的是父类在编译时就可以知道子类的信息,将多态调用转为编译期绑定,节省了虚函数调用的开销。不使用CRTP时是虚函数调用,使用CRTP时在编译期利用子类作为模板参数,提早绑定子类,而不是运行时绑定。参考:Design Patterns With C++(八)CRTP(上)。
4.1 使用CRTP实现编译时多态
虚函数版本:
#include <iostream>
#include <memory>
template<typename ChildType>
class Vehicle{
public:
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
Vehicle(const Vehicle& vehicle) = delete;
Vehicle& operator=(const Vehicle& vehicle) = delete;
virtual std::shared_ptr<Vehicle> clone() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return std::shared_ptr<Vehicle>(new ChildType(static_cast<const ChildType &>(*this)));
}
/* 此处的drive()是通过虚函数实现的,也可以不用虚函数 */
virtual void drive() {
((ChildType*)this)->drive();
}
private:
std::string band_;
};
class Car: public Vehicle<Car>{
public:
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called." << std::endl;
}
Car(const Car& car): Vehicle("Tesla"){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-ctor called." << std::endl;
}
Car& operator=(const Car& car){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-assignment called." << std::endl;
return *this;
}
/* 此处的drive()是通过虚函数实现的,也可以不用虚函数 */
virtual void drive() override {
std::cout << "Driving a car.\n";
}
};
class dummy: public Vehicle<dummy>{
public:
dummy() = default;
~dummy() = default;
dummy(const dummy&) = delete;
dummy& operator=(const dummy&) = delete;
};
int main(){
std::cout << std::string(40, '-') << std::endl;
std::shared_ptr<Vehicle<Car>> vehicle(new Car("BYD"));
vehicle->drive();
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Driving a car.
----------------------------------------
Car dtor called.
Vehicle dtor called.
非虚函数版本:
#include <iostream>
#include <memory>
template<typename ChildType>
class Vehicle{
public:
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
Vehicle(const Vehicle& vehicle) = delete;
Vehicle& operator=(const Vehicle& vehicle) = delete;
virtual std::shared_ptr<Vehicle> clone() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return std::shared_ptr<Vehicle>(new ChildType(static_cast<const ChildType &>(*this)));
}
/* 非虚函数,但结合CRTP可以实现编译时多态 */
void drive() {
((ChildType*)this)->driveImp();
}
private:
std::string band_;
};
class Car: public Vehicle<Car>{
public:
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called." << std::endl;
}
Car(const Car& car): Vehicle("Tesla"){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-ctor called." << std::endl;
}
Car& operator=(const Car& car){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-assignment called." << std::endl;
return *this;
}
/* 非虚函数,但结合CRTP可以实现编译时多态 */
void driveImp() {
std::cout << "Driving a car.\n";
}
};
class dummy: public Vehicle<dummy>{
public:
dummy() = default;
~dummy() = default;
dummy(const dummy&) = delete;
dummy& operator=(const dummy&) = delete;
};
int main(){
std::cout << std::string(40, '-') << std::endl;
std::shared_ptr<Vehicle<Car>> vehicle(new Car("BYD"));
vehicle->drive();
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Driving a car.
----------------------------------------
Car dtor called.
Vehicle dtor called.
4.2 使用虚函数实现运行时多态
#include <iostream>
#include <memory>
template<typename ChildType>
class Vehicle{
public:
Vehicle(const std::string& band):band_(band){
std::cout << "Vehicle ctor called.\n";
}
virtual ~Vehicle(){
std::cout << "Vehicle dtor called.\n";
}
Vehicle(const Vehicle& vehicle) = delete;
Vehicle& operator=(const Vehicle& vehicle) = delete;
virtual std::shared_ptr<Vehicle> clone() const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
return std::shared_ptr<Vehicle>(new ChildType(static_cast<const ChildType &>(*this)));
}
/* 虚函数,实现运行时多态 */
virtual void drive() = 0;
private:
std::string band_;
};
class Car: public Vehicle<Car>{
public:
Car(const std::string& band):Vehicle(band){
std::cout << "Car ctor called.\n";
}
~Car() {
std::cout << "Car dtor called." << std::endl;
}
Car(const Car& car): Vehicle("Tesla"){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-ctor called." << std::endl;
}
Car& operator=(const Car& car){
std::cout << __PRETTY_FUNCTION__ << ", Car copy-assignment called." << std::endl;
return *this;
}
/* 虚函数,实现运行时多态 */
virtual void drive() override {
std::cout << "Driving a car.\n";
}
};
class dummy: public Vehicle<dummy>{
public:
dummy() = default;
~dummy() = default;
dummy(const dummy&) = delete;
dummy& operator=(const dummy&) = delete;
};
int main(){
std::cout << std::string(40, '-') << std::endl;
std::shared_ptr<Vehicle<Car>> vehicle(new Car("BYD"));
vehicle->drive();
std::cout << std::string(40, '-') << std::endl;
return 0;
}
输出:
----------------------------------------
Vehicle ctor called.
Car ctor called.
Driving a car.
----------------------------------------
Car dtor called.
Vehicle dtor called.