析构函数,没有抽象基类c ++的构造函数

flu*_*fin 5 c++ inheritance c++11

我搜索了这个,但我真的不明白答案.

我对C++完全不熟悉,我想要实现的是有一个抽象类作为我的对象类型的基类,这样我就可以将我的对象存储在抽象类类型的指针数组中而不是使用void *.此外,我的对象共享一些常见的成员函数,这些函数可以通过抽象类实现轻松减少我的代码库.

但是,我对抽象类的构造函数和析构函数感到困惑.

抽象类实际上并不需要构造函数,因为可传递的参数对于两者都是通用的,需要在派生类中使用所述参数进行不同的操作以正确设置受保护的属性(矩阵的大小).那么,没有构造函数可以吗?另外,因为我没有构造函数,析构函数应该是什么?

我说一个实现虚拟析构函数的答案.但是,我不确定这意味着什么,并且讨论了潜在的内存泄漏,只要派生类重新实现了析构函数,就不会有任何内容泄漏.所以,这确实意味着我可以实现一个虚拟的decstructor,然后在派生的对象中说Foo,Bar我只是实现~Foo~Bar防止内存泄漏(假设它们当然是正确的)?我不相信我理解派生类中的重新实现意味着什么.

Kar*_*oll 8

析构函数

通常,在实现抽象基类时,您有两个推荐的析构函数选项(源代码):

1.实现公共的虚拟析构函数

当你打算拥有基类的指针时,可以使用它,这可能指向派生类的实例.例如:

class MyBase {
public:
    virtual ~MyBase() {};
};

class MyDerived : public MyBase {
public:
    virtual ~MyDerived() {};
}

std::unique_ptr<MyBase> pInstance = std::make_unique<MyDerived>();
Run Code Online (Sandbox Code Playgroud)

通过在基类(以及派生类)中使析构函数成为虚拟,您可以确保MyDerived在运行时调用析构函数.如果析构函数是非虚拟的,则调用delete指针MyBase将不会调用析构函数MyDerived.

2.实现受保护的非虚拟析构函数

如果您不希望允许用户创建派生对象的基类指针,请使用此选项.

class MyBase {
protected:
    ~MyBase() {};
};

class MyDerived : public MyBase {
public:
    ~MyDerived() {};
}

// NOT ALLOWED: std::unique_ptr tries to call protected destructor.
std::unique_ptr<MyBase> pBadInstance = std::make_unique<MyDerived>();

// Allowed: std::unique_ptr calls public MyDerived::~MyDerived()
std::unique_ptr<MyDerived> pGoodInstance = std::make_unique<MyDerived>();
Run Code Online (Sandbox Code Playgroud)

然而,这有一个重要的警告.如果您有一个深度继承层次结构,那么拥有一个非虚拟析构函数意味着您必须在层次结构中强制执行此规则.例如:

class MyBase {
protected:
    ~MyBase() {};
};

class MyDerived : public MyBase {
public:
    ~MyDerived() {};
}

class MyDerivedAgain : public MyDerived {
public:
    ~MyDerivedAgain() {};
}

// Uh oh! MyDerivedAgain destructor would not be called!
std::unique_ptr<MyDerived> pGoodInstance = std::make_unique<MyDerivedAgain>();
Run Code Online (Sandbox Code Playgroud)

如果选择使用此路由,则应确保不允许实例化任何基类.除了叶子派生类之外的所有析构函数都应该受到保护.

这看起来有点复杂,但它可以具有诸如避免vtable空间等优点,并且通过在运行时避开vtable查找来轻微改善紧密循环中的性能(最好是微优化).

构造函数

只要所有变量都可以默认构造(或者没有构造函数(例如int)),在任何类中省略构造函数都是完全可以的.C++编译器将简单地创建默认构造函数MyAbstractClass::MyAbstractClass() { }.也就是说,通常最好创建一个构造函数来初始化任何抽象类变量:

好的:

class MyBase {
protected:
    int _x;
    int _y;
};

class MyDerived : public MyBase {
public:
    MyDerived(int x, int y) {
       _x = x;
       _y = y;
    }
};
Run Code Online (Sandbox Code Playgroud)

更好:

class MyBase {
public:
    MyBase(int x, int y) : _x(x), _y(y) {
    }

protected:
    int _x;
    int _y;
};

class MyDerived : public MyBase {
public:
    MyDerived(int x, int y) : MyBase(x, y) {
    }
};
Run Code Online (Sandbox Code Playgroud)

带有MyBase::MyBase(int, int)构造函数的"Better"版本更好,因为它强制_x_y立即初始化,编译器将检查是否调用了基类构造函数.通过在派生构造函数中初始化基类变量,您可能会引发灾难,因为您可能忘记初始化变量并导致各种运行时问题.

附录:关于"接口"的注释

如果要实现定义"契约"的接口类,则可以跳过构造函数(接口没有变量或实现,不需要构造函数),并使用公共虚拟析构函数.这可以确保实现接口的任何类在删除时都会被清除.

class MyInterface {
public:
    virtual ~MyInterface() = 0;

    virtual void MyMethod() = 0;

    virtual void MyOtherMethod() = 0;
};

// Base class virtual destructors should always have an implementation,
// even when they are pure-virtual.
MyInterface::~MyInterface() { }

// -----------------------------------------------------------------------------

class MyImplementation : public MyInterface {
    virtual ~MyImplementation () { }

    virtual void MyMethod() { std::cout << "MyMethod()" << std::endl; }

    virtual void MyOtherMethod()  { std::cout << "MyOtherMethod()" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)