我刚刚在代码中修复了一个非常微妙的错误,这是由异常切片造成的,我现在想确保我完全理解发生了什么.
这是我们的基本异常类,派生类和相关函数:
class Exception
{
public:
// construction
Exception(int code, const char* format="", ...);
virtual ~Exception(void);
<snip - get/set routines and print function>
protected:
private:
int mCode; // thrower sets this
char mMessage[Exception::MessageLen]; // thrower says this FIXME: use String
};
class Derived : public Exception {
public:
Derived (const char* throwerSays) : Exception(1, throwerSays) {};
};
void innercall {
<do stuff>
throw Derived("Bad things happened!");
}
void outercall {
try {
innercall();
}
catch(Exception& e)
{
printf("Exception seen here! …
Run Code Online (Sandbox Code Playgroud) 啊,SO及时回来了.
我收到一个奇怪的错误:
'B::blah': overriding virtual function return type differs and is not covariant from 'A::blah'
Run Code Online (Sandbox Code Playgroud)
以下是导致问题的代码:
class A {
public:
class Inner { };
virtual Inner blah() = 0;
};
class B : public A {
public:
class Inner2 : public Inner { };
Inner2 blah() {
return Inner2();
}
};
Run Code Online (Sandbox Code Playgroud)
我查了一下错误,根据我在微软网站上找到的一个页面,类型可以协变的方式之一是:
返回类型B :: f中的类与D :: f的返回类型中的类相同,或者是D :: f的返回类型中类的明确的直接或间接基类,在D中可以访问
是不是Inner
和Inner2
?如果重要的话我正在使用Microsoft Visual C++ 2010.
好的,感谢John,我了解到只有指针和引用才能协变.这是为什么?可以将Derived转换为Base,那么为什么具有从同一事物派生的返回类型的虚函数不会将返回类型转换为基类的类型?在我的例子中,似乎(A*(new B))->blah()
返回一个Inner
实际上Inner2
已被抛出的东西是有道理的.
我想我理解虚方法和vtable的概念,但是我不明白为什么将对象作为指针(或引用)传递并通过值传递它(将哪种方式丢弃vtable或其他东西)之间存在差异?
为什么会这样的工作:
Material* m = new Texture;
poly->setMaterial(m);
// methods from Texture are called if I keep carrying the pointer around
Run Code Online (Sandbox Code Playgroud)
而不是这个?:
Material m = Texture();
poly->setMaterial(m);
// methods from Material are called if I pass the value around
Run Code Online (Sandbox Code Playgroud) c++ polymorphism inheritance virtual-functions object-slicing
可能重复:
虚函数对象切片
让我们考虑一下:
#include <vector>
#include <iostream>
using namespace std;
struct A {
virtual void do_it() { cout << "A" << endl; }
};
struct B : public A {
virtual void do_it() { cout << "B" << endl; }
};
int main() {
vector<A> v;
v.push_back(B());
v[0].do_it(); // output is A
}
Run Code Online (Sandbox Code Playgroud)
哪个功能会被调用?如果不存在切片,基本上可以使用不带指针的多态性吗?
标题基本概括了所有内容.基本上,这样做是合法的:
class Base {
//stuff
}
class Derived: public Base {
//more stuff
}
vector<Base> foo;
Derived bar;
foo.push_back(bar);
Run Code Online (Sandbox Code Playgroud)
基于我见过的其他帖子,以下是可以的,但我不想在这种情况下使用指针,因为它更难以使其线程安全.
vector<Base*> foo;
Derived* bar = new Derived;
foo.push_back(bar);
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用它std::enable_if
来专门化一个类,如果它的一个子类具有定义的特定成员函数.否则,它应该使用在基类中定义的默认实现.
#include <boost/mpl/list.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/tti/has_member_function.hpp>
#include <iostream>
#include <type_traits>
#include <memory>
BOOST_TTI_HAS_MEMBER_FUNCTION(f2)
class Base
{
public:
virtual double f1(double x, double y) const
{
std::cout << "Called Base Method" << std::endl;
return 0.0;
}
};
template<typename Derived>
class A : public Base
{
public:
template<typename T = Derived>
typename std::enable_if
< has_member_function_f2< T
, double
, boost::mpl::list<double>
, boost::function_types::const_qualified
>::value
, double
>::type
f1(double x, double y) const
{
std::cout << "Called Derived Method" << std::endl; …
Run Code Online (Sandbox Code Playgroud) 背景资料
我已经用Java编程了一段时间,而且我几个月前才切换到C++,所以如果答案只是我错过的傻话,我会道歉!现在已经说过了,现在是时候解决问题吧!我正在开发一个基于文本的基本游戏引擎,最近我遇到了一个有趣的具体且不太可能的问题.我尝试在下面的程序中以较小的比例测试它,并决定只显示(而不是我的实际游戏代码),以免屏蔽屏幕,并使问题更少复杂.下面建模的问题反映了我的实际代码的问题,只是没有蓬松的干扰者.
问题
本质上问题是多态性之一.我想重载输出操作符"<<"以作为显示功能,该功能对于层次结构中的每个对象都是唯一的.问题是,当我从存储这些层次结构成员的列表中调用此运算符时,它们将丢失其标识并调用基类的输出运算符.通常,人们可以通过使用简单的显示方法替换运算符重载,将显示方法标记为虚拟,并继续他们快乐的一天来解决这个问题.我并不特别介意对代码进行更改,但现在我只是好奇.有没有办法在层次结构中重载运算符,导致我在这里得到什么?
[示例]代码
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class Polygon {
friend ostream& operator<<(ostream& os, const Polygon& p);
public:
private:
};
class Rectangle : public Polygon {
friend ostream& operator<<(ostream& os, const Rectangle& r);
public:
private:
};
class Square : public Rectangle {
friend ostream& operator<<(ostream& os, const Square& s);
public:
private:
};
ostream& operator<<(ostream& os, const Polygon& p) {
os << "Polygon!" << endl;
return os;
}
ostream& operator<<(ostream& os, const Rectangle& r) …
Run Code Online (Sandbox Code Playgroud) c++ polymorphism operator-overloading non-member-functions object-slicing
我有
class Rect{
// stuff
};
Run Code Online (Sandbox Code Playgroud)
和
class SpecialRect:public Rect{
private:
operator const Rect(){return *this;} // No implicits casts to Rect
public:
// stuff
};
Run Code Online (Sandbox Code Playgroud)
SpecialRect继承了Rect的所有属性和方法,但我要避免SpecialRect到基类Rect的非显式转换。
在代码中
SpecialRect oneSpecial;
Rect aRect=oneSpecial; // I want this to not compile. (to remind-me to declare aRect as SpecialTect)
Run Code Online (Sandbox Code Playgroud)
编译没有错误。(我知道将基类Rect声明为私有可以做到这一点,但我不想重新实现其所有方法。)
有没有办法做到这一点?
std::unique_ptr
with 的行为custom deleter
基于删除程序的静态类型。没有多态性,没有基于在运行时传递的实际删除程序的运行时行为,因为提供的派生删除程序已被切片为声明的删除程序的静态类型。
(其目的是通过这种方式设计的,以允许带有
default deleter
或带有的unique_ptr的custom deleter without any data members
大小与原始指针的大小相同)。
unique_ptr
with的静态行为custom deleter
:class A {};
struct BaseDeleter {
virtual void operator()(A* p) const {
std::cout << "in BaseDeleter" << std::endl;
delete p;
}
};
struct DerivedDeleter: BaseDeleter {
void operator()(A* p) const override {
std::cout << "in DerivedDeleter" << std::endl;
delete p;
}
};
int main() {
auto unique_var = std::unique_ptr<A, BaseDeleter>(new A);
unique_var = std::unique_ptr<A, DerivedDeleter>(new A); …
Run Code Online (Sandbox Code Playgroud) 考虑下面的类Buffer
,其中包含一个std::vector
对象:
#include <vector>
#include <cstddef>
class Buffer {
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val) {}
};
Run Code Online (Sandbox Code Playgroud)
现在,考虑make_zeroed_buffer()
下面的功能。该类BufferBuilder
是从中公开派生的本地类Buffer
。其目的是创建Buffer
对象。
Buffer make_zeroed_buffer() {
struct BufferBuilder: Buffer {
BufferBuilder(): Buffer(std::byte{0}) {}
};
BufferBuilder buffer;
// ...
return buffer;
}
Run Code Online (Sandbox Code Playgroud)
如果没有进行复制清除,是否buffer
可以保证将上面的物体移走?
我的推理如下:
buffer
的return
语句是一个左值。由于它是不再使用的本地对象,因此编译器将其转换为rvalue。buffer
对象是类型BufferBuilder
。Buffer
是的公共基类BufferBuilder
,因此此BufferBuilder
对象隐式转换为Buffer
对象。BufferBuilder
对的引用 …c++ ×10
object-slicing ×10
polymorphism ×3
inheritance ×2
c++11 ×1
c++17 ×1
casting ×1
covariance ×1
enable-if ×1
exception ×1
return-type ×1
unique-ptr ×1
vector ×1