代码之家  ›  专栏  ›  技术社区  ›  serkan ertas

如何调用运算符=或超类的析构函数?

  •  1
  • serkan ertas  · 技术社区  · 2 年前

    我有一个具有堆成员“name”的A类:

    class A {
    protected:
        char *name;
    
    public:
        // Constructor
        A() {
            name = new char[10];
            strcpy(name, "Undefined");
        }
    
        // Assignment Operator
        virtual A &operator=(const A &rhs) {
            if (this == &rhs) {
                return *this;
            }
    
            delete [] name;
            name = new char[10];
            strcpy(name, rhs.name);
    
            return *this;
        }
    
        // Destructor
        virtual ~A() {
            delete [] name;
        }
    };
    

    我有带有附加变量“B”的子类B:

    class B : public A {
        int b;
    
        // Constructor
        B():A(),b(0){}
    
        // Assignment Operator
        virtual B& operator=(const B& rhs) {
            if (this == &rhs) {
                return *this;
            }
    
            delete [] name;
            name = new char[10];
            strcpy(name, rhs.name);
    
            b = rhs.b;
    
            return *this;
        }
    
        // Destructor
        virtual ~B() {
            delete [] name;
        }
    };
    

    我有一个子类C,它有额外的成员“char*name”:

    class C : public A {
        int* c;
    
        // Constructor
        C():A() {
            c = new int[10];
            for(int i = 0 ; i < 10 ; i++) {
                c[i] = 0;
            }
        }
    
        // Assignment Operator
        virtual C& operator=(const C& rhs) {
            if (this == &rhs) {
                return *this;
            }
    
            delete [] name;
            name = new char[10];
            strcpy(name, rhs.name);
    
            delete [] c;
            c = new int[10];
            for (int i = 0 ; i < 10 ; i++) {
                c[i] = rhs.c[i];
            }
    
            return *this;
        }
    
        // Destructor
        virtual ~C() {
            delete [] name;
            delete [] c;
        }
    };
    

    我想知道这是否是实现运算符=和B和C的析构函数的正确方法。 有没有办法在B或C中调用A的运算符=或析构函数,这样我就不会一次又一次地为所有成员编写赋值了。

    • A是具有堆变量的基类
    • B是从a派生的类,带有附加的“int B”
    • C是从a派生的类,带有附加的“char*name”
    1 回复  |  直到 2 年前
        1
  •  2
  •   Peter    2 年前

    回答所问的问题,是的,派生类 operator=() 可以调用基类 操作人员 例如

        B& operator=(const B& rhs) {
           A::operator=(rhs);
           b = rhs.b;
           return *this;  
        }
    

    (同样适用于 C ).

    然而,这不是一个特别好的方法。在下文中,我将解决您对方法的一些担忧,这些担忧是您没有问过的。

    1. 没有必要 操作人员 是虚拟的。

    2. 最好不要声明或定义 B::operator=() 完全允许这样做 B: :运算符=() 成为 含蓄地 生成(例如由编译器生成),而隐式生成的版本调用基类版本,并按值复制/分配所有成员。滚动自己的唯一原因是如果隐式生成 操作人员 不适合您的派生类。

    此外,没有必要执行 if (this == &rhs) 在里面 A::operator=() 。相反,它可以定义为

    A &operator=(const A &rhs) {
        char *newname = new char [std::strlen(rhs.name)];
        strcpy(newname, rhs.name);
        delete [] name;
        name = newname;
        return *this;
    }
    

    除了避免 this == &rhs 测试(如果 A 有一个 operator&() ),这种方法也是非常安全的-如果 new 表达式抛出,对象不变。

    这样做的唯一缺点是,暂时会有少量额外的内存使用( name , rhs.name newname 所有消耗内存,之前 名称 被释放并重新分配)。

    使用这种方法, C::operator=() 将被实现为调用 A: :运算符=() 以及分配/复制/发布 c .

    此外,的析构函数 B C 通常不应释放 A. 的成员。什么时候 B C 被破坏, A. 的构造函数是隐式调用的(因此您的方法将导致 A::name 被破坏两次,从而导致未定义的行为。

    最后,您可以使用标准容器( std::string std::vector<char> ,并避免了手动分配内存的需要( delete 完全查阅“零规则C++”了解更多信息。