C++子类模块化函数
C++ subclasses modular functions
抱歉,我决定从根本上更新问题,因为代码充满了我的错误并且没有传达我的观点。
我想看看以下内容是否可行:
下面是一个可以编译的示例:
#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/
- 能够成功工作;可行
如果它有效,它是可行的。
在您的情况下,它有效。但是,请考虑以下 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
。
因此,这里清楚地显示了这个问题,Advanced1 和 Advanced2 指向一个类型为 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_function
,TestB::common_function
或TestC::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和基本,现在它有完全不同的名称。
- 为什么当我解模块化时,这个C++代代码"效率较低"?
- 如何使用非默认构造函数实例化模板化类
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 如何在 C++ 中使用它的构造函数初始化 unique_ptrs 的 2D 向量?
- 我们是否需要为 C++ 中的多个函数初始化多个模板?
- 电源功能模块化操作
- 如何为模块化应用程序实现C++插件系统
- Arduino 模块化编程与全局和设置
- 在C++中使用默认构造函数初始化对象的不同方法
- 使用默认构造函数初始化对象的不同方法
- 我们可以用参数化构造函数初始化结构的数组吗?
- C++:快速模块化指数
- 有没有办法使用该类的构造函数初始化另一个类的私有部分内的对象数组?
- C++ - 使用另一个类的构造函数实例化一个对象
- 类内初始化与构造函数初始化列表的顺序
- 通过 C++ 中的重载构造函数初始化未知类型的变量
- 使用复制构造函数初始化 new[]
- 如何从子类的构造函数初始化父类的私有成员
- C++子类模块化函数