不从基类 C++ 继承
Not Inherit from Base Class C++
让我直截了当。这是一个面试问题,我至今无法解决。考虑两个类
class A
{
public : virtual int f() { };
int a;
}
class B : public A
{
public : virtual int g() { };
int b;
}
当被问及 A 和 B 的大小时,我说对了 8 和 12。下一个问题是如何定义类 B,使其忽略从 A 派生的前 8 个字节。他说这是可能的。我仍然不明白这怎么可能。谁能解释一下这是怎么做到的?
编辑:真正的问题不是找到类的大小,而是后续。
我不确定提问者期待什么答案,但这里有一些可能的解决方案:
将"A"作为指针:
//Only takes 4 or 8 bytes (32 bit vs 64 bit code) for 'A', regardless of 'A's actual size, but must point to an 'A' located elsewhere in memory with the full size.
class B
{
A *a; //Only 4 bytes.
int b;
};
将"A"设为静态:
//Doesn't assume any of 'A's size, but all instances of 'B' shares a single instance of 'A'.
class B
{
static A a;
int b;
};
将"A"传递给"B"的函数:
//Pass in the reference to 'a' when needed, so multiple 'B's can share the same 'a' explicitly when desired.
class B
{
void q(A &a) { this->b + a.a; return a.g(); }
};
使"A"和"B"没有虚拟表(可能是面试官的观点(
//By not having virtual functions, you save the (really small) cost of 4 bytes (8 bytes on 64 bit machines)
class A
{
public:
int f() { }; //Not virtual
int a;
}
class B : public A
{
public:
int g() { }; //Not virtual
int b;
}
它仍然花费你A::a的大小,除非你在B中重复使用"a"而不是B::b,否则你无法避免这4个字节。重用一个变量来完全表示其他东西可能是编程习惯非常糟糕的标志。
将 A'a 和 B 的变量联合化,并将函数放在一个类中
class AB //Only 4 bytes total
{
public:
union
{
int a;
int b;
};
void f();
void g();
};
关于这一点的坏主意是,您必须跟踪是否应该访问"a"或"b",因为它们都占用相同的 4 字节内存,并且它们不能同时使用它。
另一个不好的事情是,这表明班级的责任太大了。是A还是B?如果两者兼而有之,最重要的问题应该是,"为什么两者兼而有之?它应该有一个单一的责任,而不是一个混合目的的铁板一块。
将"A"设为模板,并从A<B>
继承:
template<typename TypeB>
class A
{
int a;
};
//Saves the cost of the virtual table... not that that really matters.
class B : public A<B>
{
int b;
};
最后一个被称为"奇怪的重复模板模式"(CRTP(这个想法是继承的"A<B>
"可以从"B"调用访问变量和函数(如果将B的"this"指针传递到A的构造函数中(,并且"B"可以直接从"A<B>
"访问变量和函数。
您继承自为"B"生成的模板"A"的编译时生成版本。
这并不能直接回答面试官的问题,但操纵 A 和 B 继承的另一种可能方法是做这样的事情:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
//This concept was taken from a Going Native 2013 talk called "C++ Seasoning" given by Sean Parent
//
//Located here: (about 101 minutes into it)
//http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
//Polymorphism without inheritance.
//Permits polymorphism without using pointers or references,
//and allows them to be copied around easier (each instance is actually its own object) rather
//than accidentally shallow-copying when you wanted deep-copies.
//
//Every time Object::Print() is called, it calls
// Object::PrintableConcept::Print(), which virtually calls
// Object::PrintableModel<TYPE>::Print(), which calls your
// "derived" class that implements the Print() function, regardless
// of what that class inherits (if anything).
class Object //Class without inheritance or virtual.
{
public:
template<typename Type>
Object(Type instance) : self(std::make_shared<PrintableModel<Type>>(std::move(instance)))
{ }
//Calls the "inherited" function.
void Print() const
{
self->Print();
}
private:
struct PrintableConcept //The concept we want to polymorphably access.
{
virtual ~PrintableConcept() = default;
virtual void Print() const = 0;
};
//The class that concretely models the concept,
//and does the actual inheritting.
template<typename Type>
struct PrintableModel : public PrintableConcept
{
PrintableModel(Type instance) : data(std::move(instance)) { }
//Every time
void Print() const override
{
this->data.Print();
}
Type data;
};
//This should be a unique_ptr, but you also need to make sure
//you implement proper copy operators in this class and move support.
std::shared_ptr<PrintableConcept> self;
};
class Whatever
{
public:
void Print() const { std::cout << "Whatevern" << std::endl; }
};
class SomethingElse
{
public:
void Print() const { std::cout << "SomethingElsen" << std::endl; }
};
class WidgetThing
{
public:
void Print() const { std::cout << "WidgetThingn" << std::endl; }
};
typedef std::vector<Object> Document;
int main()
{
Document document;
document.emplace_back(Whatever());
document.emplace_back(SomethingElse());
document.emplace_back(WidgetThing());
for(const auto &object : document)
{
object.Print();
}
return 0;
}
<<<运行代码>>>
实际上没有一个类继承自"Object"(或其他任何东西(,但可以在向量中互换使用,因为它们都实现了对象模板化访问的公共接口(PrintableConcept
(,但对象本身不是模板,因此不会成为Object<something>
和Object<something-else>
这将是单独的类型。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象