C++子类模块化函数

C++ subclasses modular functions

本文关键字:函数 模块化 子类 C++      更新时间:2023-10-16

抱歉,我决定从根本上更新问题,因为代码充满了我的错误并且没有传达我的观点。

我想看看以下内容是否可行:

下面是一个可以编译的示例:

#include <stdio.h>
class TestA
{
    public:
        int A;
        TestA(){A = 1;}
        const TestA &operator=(const TestA &Copy)
        {
            A = Copy.A;
        }
};
class TestB : public TestA
{
    public:
        using TestA::operator=;
        void AdvancedFunction1(){A = A + A;}
};

int main()
{
    TestA Test;
    TestB *Alt;
    TestB Alt2;
    Alt = (TestB *)&Test;
    printf("%d!n",Test.A);
    Alt->AdvancedFunction1();
    printf("%d!n",Test.A);
    Test = Alt2;
    printf("%d!n",Test.A);
    return 0;
}

假设 TestB 可以(通过强制转换(指向 TestA,并且可以成功修改 TestA,这是一个可行的概念吗?它似乎有效,有什么陷阱?(我知道人们说这是错误的,但除了"惯例"之外,它还有什么特别的问题?

vi·a·ble

形容词/ˈvīəbəl/

  1. 能够成功工作;可行

如果它有效,它是可行的。

在您的情况下,它有效。但是,请考虑以下 2 种情况n:

-您可以添加虚拟功能。这将导致它崩溃。

-您可以更改AdvancedFunction1()以便它对类 TestB 的成员进行操作,这将导致未定义的行为,因为您的对象不是 TestB 类型,并且没有 TestB 的成员。

编辑:

崩溃代码:

class TestA
{
    public:
        int A;
        TestA(){A = 1;}
        const TestA &operator=(const TestA &Copy)
        {
            A = Copy.A;
        return *this;
        }
};
class TestB : public TestA
{
    public:
        using TestA::operator=;
        void AdvancedFunction1(){A = A + A;}
    virtual void f()
    {
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    TestA Test;
    TestB *Alt;
    Alt = (TestB *)&Test;
    Alt->AdvancedFunction1();
    Alt->f(); //crash here
    return 0;
}

我不会这样做 - 正确使用继承,即

TestA* Advanced1 = new TestB;
TestA* Advanced2 = new TestC;
// your previous code at this point is wrong - these functions should be virtual in base class and overridden in derived classes...
Advanced1->AdvancedFunction1(); // This now does what you want
Advanced2->AdvancedFunction2(); // and so does this...

作业很好...

你的方法的问题在于,如果你有虚函数(多重继承(,或者在某些时候你决定TestB需要成员等,会发生什么。在很多层面上,这是一种错误的方法......

你正在做的事情称为向上转换。向上转换是指获取指向派生类型的指针并尝试将其分配给基类型。它不起作用。

只允许将指针隐式强制转换为其基类之一类型的指针。你可以将TestB*TestC*强制转换为TestA*,但不能将TestB*隐式强制转换为TestC*,或将TestA*隐式强制转换为其任何一个子类。所以你的示例甚至不会编译。

原因是,如您的示例所示,如果可以将基指针强制转换为派生指针,则可以在基指针上调用派生函数,这会导致许多问题,因为您将尝试访问派生的成员变量,而它们将不存在。

可以通过显式强制转换来执行此操作,但如果这样做,如果基础类型确实不是从要强制转换为的基类型派生的,则很可能会出现段错误。如果您的类是多态的,则可以使用 dynamic_cast 安全地执行此操作,当您尝试将派生指针强制转换为非派生类型的基指针时,它会返回NULL

No.

首先,这些方法在您的示例中不是静态的,因此您无法从类类型访问它们。您需要一个对象的实例。

现在让我们假设你的意思是:

Advanced1->AdvancedFunction1(); 
Advanced2->AdvancedFunction2();

TestB公开扩展TestA ,因此它具有所有功能以及更多功能。所以TestB是一个TestA.

但是TestA不是TestB,所以你不能给TestB分配TestA

因此,这里清楚地显示了这个问题,Advanced1Advanced2 指向一个类型为 Base 的对象,该对象根本没有该方法。因此,您不能指向功能少于声明变量的类型的内容。

TestB *Advanced1 = &Basic;//这可行吗?

,因为向上投射不是一个好主意。

您应该使用多态性,方法是在基中创建虚函数,然后在派生中覆盖该函数。

如果要在派生类中使用变量 A,则应对其进行保护,因为如果变量是私有的,则不能通过公共继承使用它。

TestA Basic;
TestB *Advanced1 = &Basic; //Is this viable?
TestC *Advanced2 = &Basic; //And this?

不可以,孩子不能指向父亲类型的对象。

TestB->AdvancedFunction1(); //Does this do what I think it does?
TestC->AdvancedFunction2(); //Or do implicit errors/problems occur?

它调用TestB::AdvancedFunction1(也就是说,如果你强制(转换(和基本到高级1(。结果可能是灾难性的。

TestB AdvVar1;
TestC AdvVar2;
AdvVar1 = Basic; //Does this do what is intended? 
AdvVar2 = Basic; //Or do implicit errors occur?

一点也不。尽管有时向下转换(将父亲转换为孩子(可能是合理的,但复制(除非定义了运算符 =(不起作用。

你应该做什么,如果你想有一个孩子列表,所有的孩子都指向父亲,这是你应该做的:

class TestA
{
public:
    enum _type
    {
         IS_TESTA = 0,
         IS_TESTB,
         IS_TESTC
    } type;
    /* other variables */
    TestA() {type = IS_TESTA;}
    virtual void common_function() { /* do something with TestA data */ }
    void father_function() {}
}
class TestB : public TestA
{
public:
    /* variables */
    TestB() {type = TestA::IS_TESTB;}
    void common_function() { /* do something with TestA & TestB data */ }
    void TestB_specific_function() {}
}
class TestC : public TestA
{
public:
    /* variables */
    TestC() {type = TestA::IS_TESTC;}
    void common_function() { /* do something with TestA & TestC data */ }
    void TestC_specific_function() {}
}

要创建列表,请执行以下操作:

TestA **list = new TestA *[size];
for (int i = 0; i < size; ++i)
    if (for_any_reason_create_TestB)
        list[i] = new TestB;
    else if (for_any_reason_create_TestC)
        list[i] = new TestC;
    else
        list[i] = new TestA;
现在,当你想

使用变量时,当你想调用所有人共享的函数时,即使每个子类都以不同的方式实现它,你可以这样做:

for (int i = 0; i < size; ++i)
    list[i]->common_function();

它会自动调用TestA::common_functionTestB::common_functionTestC::common_function,具体取决于实际对象类型。

如果要调用特定的子函数,可以这样做(但不建议这样做(:

for (int i = 0; i < size; ++i)
    if (list[i]->type == TestA::IS_TESTB)
        ((TestB *)list[i])->TestB_specific_function();
    else if (list[i]->type == TestA::IS_TESTC)
        ((TestC *)list[i])->TestC_specific_function();

上面的代码调用了未定义行为的守护进程。它是形式上无效的代码(前提是您添加了static_cast,否则它将无法编译(,编译器将很乐意发明如何将您的猫变成黑色的方法。

GCC尤其以其惩罚敢于召唤野兽的程序员的创造力而闻名。在您的情况下,很有可能将相同的值常量传播到两个函数中,因为规范说 Advanced1 和 Advanced2 不能指向同一个对象或优化调用,因为规范说两者都不能指向与 Basic 相同的对象,尽管所有迹象表明它们实际上确实如此。相信我,如果它在某些创意代码中深入执行这样的事情,则很难调试。

请注意,由于函数不是虚拟的,因此除了正式函数之外,方法和(可能重载的(自由函数之间绝对没有区别。所以没有什么能阻止你简单地写:

void AdvancedFunction1(TestA &that) { that.A = that.A + that.A; }

并且比:

TestA test;
AdvancedFunction1(test);

附带说明:当你已经有一些答案时,完全重新设计问题是非常非常愚蠢的行为。问题的第一个版本有高级1和高级2和基本,现在它有完全不同的名称。